Introduction To Verilog & Modelsim: Hardware Description Languages (HDL)
Introduction To Verilog & Modelsim: Hardware Description Languages (HDL)
A specified computer language used to program the structure, design and operation of electronic
circuits commonly digital logic circuits. HDL’s also began to be used for system-level design. They
were used for the simulation of system boards, interconnect buses, FPGAs and PALs (Programmable
Array Logic). A common approach is to design each IC chip using an HDL and then verify system
functionality via simulation. Verilog HDL has evolved as a standard hardware description language.
It is a general purpose hardware description language that is easy to learn and use. It is similar in
syntax to the C programming language. Designers use it as a standard language to describe digital
circuits.
Basic Concepts
Verilog HDL is a case-sensitive language. All keywords are in lowercase.
Comments
Comments can be inserted in the code for readability and documentation. There are two ways to
write comments. A one-line comment starts with "//". Verilog skips from that point to the end of line.
A multiple-line comment starts with "/*" and ends with "*/".
Operators
Operators are of three types: unary, binary, and ternary. Unary operators precede the operand. Binary
operators appear between two operands. Ternary operators have two separate operators that separate
three operands.
Number Specification
There are two types of number specification in Verilog: sized and unsized.
Sized Numbers
Sized numbers are represented as <size> '<base format> <number>.<size> is written only in decimal
and specifies the number of bits in the number. Legal base formats are decimal ('d or 'D),
hexadecimal ('h or 'H), binary ('b or 'B) and octal ('o or 'O). The number is specified as consecutive
digits from 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f. Only a subset of these digits is legal for a
particular base. Uppercase letters are legal for number specification.
Unsized Numbers
Numbers that are specified without a <base format> specification are decimal numbers by default.
Numbers that are written without a <size> specification have a default number of bits that is
simulator- and machine-specific (must be at least 32).
X or Z values
Verilog has two symbols for unknown and high impedance values. These values are very important
for modeling real circuits. An unknown value is denoted by an x. A high impedance value is denoted
by z.
An x or z sets four bits for a number in the hexadecimal base, three bits for a number in the octal
base, and one bit for a number in the binary base.
Strings
A string is a sequence of characters that are enclosed by double quotes. The restriction on a string is
that it must be contained on a single line, that is, without a carriage return. It cannot be on multiple
lines.
Nets
Nets represent connections between hardware elements. Just as in real circuits, nets have values
continuously driven on them by the outputs of devices that they are connected to. In Figure 3-1 net a
is connected to the output of and gate g1. Net a will continuously assume the value computed at the
output of gate g1, which is b & c.
Nets are declared primarily with the keyword wire. Nets are one-bit values by default unless they are
declared explicitly as vectors. The terms wire and net are often used interchangeably. The default
value of a net is z (except the trireg net, which defaults to x ). Nets get the output value of their
drivers. If a net has no driver, it gets the value z.
Note that net is not a keyword but represents a class of data types such as wire, wand, wor, tri, triand,
trior, trireg, etc. The wire declaration is used most frequently.
Registers
Registers represent data storage elements. Registers retain value until another value is placed onto
them. Do not confuse the term registers in Verilog with hardware registers built from edge-triggered
flipflops in real circuits. In Verilog, the term register merely means a variable that can hold a value.
Unlike a net, a register does not need a driver. Verilog registers do not need a clock as hardware
registers do. Values of registers can be changed anytime in a simulation by assigning a new value to
the register. Register data types are commonly declared by the keyword reg. The default value for a
reg data type is x.
Integer, Real, and Time Register Data Types
Integer, real, and time register data types are supported in Verilog.
Integer
An integer is a general purpose register data type used for manipulating quantities. Integers are
declared by the keyword integer. Although it is possible to use reg as a general-purpose variable, it is
more convenient to declare an integer variable for purposes such as counting. The default width for
an integer is the host-machine word size, which is implementation-specific but is at least 32 bits.
Registers declared as data type reg store values as unsigned quantities, whereas integers store values
as signed quantities.
Real
Real number constants and real register data types are declared with the keyword real. They can be
specified in decimal notation (e.g., 3.14) or in scientific notation (e.g., 3e6, which is 3 x 106 ). Real
numbers cannot have a range declaration, and their default value is 0. When a real value is assigned
to an integer, the real number is rounded off to the nearest integer.
Time
Verilog simulation is done with respect to simulation time. A special time register data type is used
in Verilog to store simulation time. A time variable is declared with the keyword time. The width for
time register data types is implementation-specific but is at least 64 bits. The system function $time
is invoked to get the current simulation time.
Simulation time is measured in terms of simulation seconds. The unit is denoted by s, the same as
real time.
Vectors
Nets or reg data types can be declared as vectors (multiple bit widths). If bit width is not specified, the
default is scalar (1-bit).
Vectors can be declared at [high# : low#] or [low# : high#], but the left number in the squared
brackets is always the most significant bit of the vector. In the example shown above, bit 0 is the
most significant bit of vector virtual_addr.
The starting bit of the part select can be varied, but the width has to be constant. The following
example shows the use of variable vector part select:
Arrays
Arrays are allowed in Verilog for reg, integer, time, real, realtime and vector register data types.
Multi-dimensional arrays can also be declared with any number of dimensions. Arrays of nets can
also be used to connect ports of generated instances. Each element of the array can be used in the
same fashion as a scalar or vector net. Arrays are accessed by <array_name>[<subscript>].
It is important not to confuse arrays with net or register vectors. A vector is a single element that is
n-bits wide. On the other hand, arrays are multiple elements that are 1-bit or n-bits wide.
Strings
Strings can be stored in reg. The width of the register variables must be large enough to hold the
string. Each character in the string takes up 8 bits (1 byte). If the width of the register is greater than
the size of the string, Verilog fills bits to the left of the string with zeros. If the register width is
smaller than the string width, Verilog truncates the leftmost bits of the string. It is always safe to
declare a string that is slightly wider than necessary.
In this section, we introduce two special concepts used in Verilog: system tasks and compiler
directives.
System Tasks
Verilog provides standard system tasks for certain routine operations. All system tasks appear in the
form $<keyword>. Operations such as displaying on the screen, monitoring values of nets, stopping,
and finishing are done by system tasks. We will discuss only the most useful system tasks.
Displaying information
$display is the main system task for displaying values of variables or strings or expressions. This is
one of the most useful tasks in Verilog. The format of $display is very similar to printf in C. A $display
inserts a newline at the end of the string by default. A $display without any arguments produces a
newline. Strings can be formatted using the specifications listed in Table 3-4.
Table 3-4. String Format Specifications
Monitoring information
Verilog provides a mechanism to monitor a signal when its value changes. This facility is provided
by the $monitor task. A format similar to the $display task is used in the $monitor task. $monitor
continuously monitors the values of the variables or signals specified in the parameter list and
displays all parameters in the list whenever the value of any one variable or signal changes. Unlike
$display, $monitor needs to be invoked only once. Examples of monitoring statements are given in
Example 3-5. Note the use of $time in the $monitor statement.
Example 3-5 Monitor Statement
Compiler Directives
Compiler directives are provided in Verilog. All compiler directives are defined by using the
`<keyword> construct. We deal with the two most useful compiler directives.
`define
The `define directive is used to define text macros in Verilog (see Example 3-7). The Verilog
compiler substitutes the text of the macro wherever it encounters a `<macro_name>. This is similar
to the #define construct in C. The defined constants or text macros are used in the Verilog code by
preceding them with a ` (back tick).
`include
The `include directive allows you to include entire contents of a Verilog source file in another
Verilog file during compilation. This works similarly to the #include in the C programming
language. This directive is typically used to include header files, which typically contain global or
commonly used definitions (see Example 3-8).
Design Methodologies and Structure of a Verilog Program
There are two basic types of digital design methodologies: a top-down design methodology and a
bottom-up design methodology. In a top-down design methodology, we define the top-level block
and identify the sub-blocks necessary to build the top-level block. We further subdivide the sub-
blocks until we come to leaf cells, which are the cells that cannot further be divided. Figure 2-1
shows the top-down design process.
To illustrate these hierarchical modeling concepts, let us consider the design of a negative edge-
triggered 4-bit ripple carry counter. The ripple carry counter shown below is made up of negative
edge triggered toggle flipflops (T_FF). Each of the T_FFs can be made up from negative edge-
triggered D-flipflops (D_FF) and inverters (assuming q_bar output is not available on the D_FF), as
shown below.
Thus, the ripple carry counter is built in a hierarchical fashion by using building blocks. The diagram
for the design hierarchy is shown below.
In a top-down design methodology, we first have to specify the functionality of the ripple carry
counter, which is the top-level block. Then, we implement the counter with T_FFs. We build the
T_FFs from the D_FF and an additional inverter gate. Thus, we break bigger blocks into smaller
building sub-blocks until we decide that we cannot break up the blocks any further.
Modules
We now relate these hierarchical modeling concepts to Verilog. Verilog provides the concept of a
module. A module is the basic building block in Verilog. A module can be an element or a collection
of lower-level design blocks. Typically, elements are grouped into modules to provide common
functionality that is used at many places in the design. A module provides the necessary functionality
to the higher-level block through its port interface (inputs and outputs), but hides the internal
implementation. This allows the designer to modify module internals without affecting the rest of the
design.
In ripple carry counter, T_FF, D_FF are examples of modules. In Verilog, a module is declared by
the keyword module. A corresponding keyword endmodule must appear at the end of the module
definition. Each module must have a module_name, which is the identifier for the module, and a
module_terminal_list, which describes the input and output terminals of the module.
• Dataflow level
At this level, the module is designed by specifying the data flow. The designer is aware of how data
flows between hardware registers and how the data is processed in the design.
• Gate level
The module is implemented in terms of logic gates and interconnections between these gates. Design
at this level is similar to describing a design in terms of a gate-level logic diagram.
• Switch level
This is the lowest level of abstraction provided by Verilog. A module can be implemented in terms
of switches, storage nodes, and the interconnections between them. Design at this level requires
knowledge of switch-level implementation details.
Verilog allows the designer to mix and match all four levels of abstractions in a design. In the digital
design community, the term register transfer level (RTL) is frequently used for a Verilog
description that uses a combination of behavioral and dataflow constructs and is acceptable to logic
synthesis tools.
Instances
A module provides a template from which you can create actual objects. When a module is invoked,
Verilog creates a unique object from the template. Each object has its own name, variables,
parameters, and I/O interface. The process of creating objects from a module template is called
instantiation, and the objects are called instances.
In the above example, the top-level block creates four instances from the T-flipflop (T_FF) template.
Each T_FF instantiates a D_FF and an inverter gate. Each instance must be given a unique name.
Note that // is used to denote single-line comments.
In Verilog, it is illegal to nest modules. One module definition cannot contain another module
definition within the module and endmodule statements. Instead, a module definition can incorporate
copies of other modules by instantiating them. It is important not to confuse module definitions and
instances of a module. Module definitions simply specify how the module will work, its internals,
and its interface. Modules must be instantiated for use in the design.
Since T_FF instantiates D_FF, we must now define the internals of module D_FF. We assume
asynchronous reset for the D_FFF.
Stimulus Block
All modules have been defined down to the lowest-level leaf cells in the design methodology. The
design block is now complete. To illustrate the concepts discussed in the previous sections, let us
build the complete simulation of a ripple carry counter. We have defined the design block and now
the stimulus block. We will apply stimulus to the design block and monitor the outputs. We must
now write the stimulus block to check if the ripple carry counter design is functioning correctly. In
this case, we must control the signals clk and reset so that the regular function of the ripple carry
counter and the asynchronous reset mechanism are both tested. We use the waveforms shown below
to test the design. Waveforms for clk, reset, and 4-bit output q are shown. The cycle time for clk is
10 units; the reset signal stays up from time 0 to 15 and then goes up again from time 195 to 205.
Output q counts from 0 to 15.
Once the stimulus block is completed, we are ready to run the simulation and verify the functional
correctness of the design block. The output obtained when stimulus and design blocks are simulated
is shown below: