System Verilog enhancements Over Verilog 2001

SystemVerilog is not a new hardware description language. SystemVerilog is a rich set of extensions to the existing Verilog HDL. In my work as a Verilog and SystemVerilog consultant and trainer, I have occasionally heard engineers make comments such as, “I’m not doing system level design, so I don’t need SystemVerilog.” That is a misconception!

It is true that the primary goal of SystemVerilog is to enable modeling and verifying large, complex designs. However, SystemVerilog provides enhancements to Verilog that every engineer can and should take advantage of. SystemVerilog makes it easier to model with Verilog, and helps ensure that models will both simulate and synthesize correctly.

This article dispels the false impression that only system-level designers need SystemVerilog. The article briefly describes 14 enhancements to Verilog that will be of interest to all Verilog users, no matter what type of designs they are modeling. SystemVerilog has much, much more to offer. As engineers become familiar with all of SystemVerilog, they will discover many other enhancements that will be useful in their day to day engineering work.

1. Time unit and precision

In Verilog, time values are specified as a number, without any time unit. For example:

forever #5 clock = ~clock;

The Verilog standard does not specify a default unit or time precision (where precision is the maximum number of decimal places used in time values). The time units and precision are properties of a software tool, set by the compiler directive ‘timescale. There is an inherent danger with compiler directives, however, because they are dependent on source code order. This can potentially cause different simulation runs to have different results.

SystemVerilog adds two enhancements to control the time units of time values. First, time values can have an explicit unit specified. The unit is one of s, ms, ns, ps or fs, representing seconds down to femtoseconds. For example:

forever #5ns clock = ~clock;

Second, SystemVerilog allows the time units and time precision to be specified with new keywords, timeunit and timeprecision. These declarations can be specified within a module, thus making time units and precision part of the model, instead of a command to a software tool.

timeunits 1ns;
timeprecision 10ps;

2. Filling vectors

With Verilog, it is easy to fill a vector of any width with all zeros, all Zs, or all Xs. However, Verilog does not have a simple way to fill a vector of any width with all ones. SystemVerilog adds a convenient shortcut to fill all the bits of a vector with the same value. The simple syntax is‘0, ‘1, ‘z or ‘x. This allows a vector of any size to be filled, without having to explicitly specify the vector size of the literal value.

bit [63:0] data;
data = ‘1; //set all bits of data to 1

3. Abstract data types

Verilog provides hardware-centric net and variable data types. These types represent 4-state logic values, and are used to model and verify hardware behavior at a detailed level. Verilog’s net data types also have multiple strength levels and resolution functions for zero or multiple drivers of the net.

SystemVerilog adds several new data types to Verilog, which allows modeling designs at more abstract levels.

  • byte — a 2-state signed variable that is defined to be exactly 8 bits.
  • shortint — a 2-state signed variable that is defined to be exactly 16 bits.
  • int — a 2-state signed variable that is similar to the C int data type, but is defined to be exactly 32 bits.
  • longint — a 2-state signed variable that is defined to be exactly 64 bits, similar to the C long type.
  • bit — a 2-state unsigned data type of any vector width that can be used in place of the Verilog reg data type.
  • logic — a 4-state unsigned data type of any vector width that can be used in place of the reg data type.
  • shortreal — a 2-state single-precision floating point variable that is the same as the C float type.
  • void — represents no value, and can be specified as the return value of a function, the same as in C.

The SystemVerilog 2-state data types allow modeling designs at a more natural level. Most digital logic works with just zeros and ones. The special value of Z is only needed to represent tri-state logic, which is rare in most designs. The special value of X is not a modeling value. It is a simulation value indicating an unknown condition.

The SystemVerilog logic data type is a synonym for the Verilog reg data type. It solves a terminology problem that has plagued new Verilog users since the dawn of RTL synthesis. The reg keyword would seem to imply “register”, which would then seem to imply that each place areg data type is used a hardware register is required.

With experience, Verilog users learn that this implication is false. The reg data type is simply a programming variable. It is the context in which the variable is used that determines whether or not a hardware register is required. The logic data type is the same as the reg type, but does not have a misleading name.

4. Relaxed rules for variables

With Verilog, variables can only be used on the left-hand side of procedural assignments. It is illegal to use a variable on the left-hand side of continuous assignments or on the receiving side of a module port. These contexts require a net data type, such as wire.

This restriction on variables is often a source of frustration. When creating a module, a designer must first determine how a signal will receive its values, in order to know what data type to use. If the way the functionality of a design is modeled changes, it is often necessary to go back and change data type declarations.

SystemVerilog relaxes the rules on the usage of variables. A variable can be:

  • Assigned values by any number of procedural assignment statements.
  • Assigned a value by a single continuous assignment statement.
  • Connected to the output of a single primitive.
  • Connected to the receiving side of a single module port.

These relaxed rules simplify creating Verilog models. Almost all signals can be declared as a variable, without concern for how the variable will receive its values. The only time a net data type is required is when a signal will have multiple drivers, such as on a bidirectional port.

The SystemVerilog rules for variables require that a variable can only have a single source for its value (from the list above). If, for example, a variable were used on the left-hand side of a continuous assignment, and the same variable was unintentionally connected to the input port of the module, an error would be reported. Verilog would have required net types in this context, which would allow unintentional multi-driver logic to compile, resulting in functional errors.

5. User defined types

Verilog does not allow users to define new data types. SystemVerilog provides a method to define new data types using typedef, similar to C. The user-defined type can then be used in declarations the same as with any data type.

typedef int unsigned uint;
uint a, b;

6. Enumerated types

In Verilog, all signals must be a net, variable, or parameter data type. Signals of these data types can have any value within their legal range. The Verilog language does not provide a way to limit the set of legal values for a variable.

SystemVerilog allows users to define enumerated types, using a C-like syntax. An enumerated type has one of a set of named values. These named values are the only legal values for that enumerated variable.

enum {WAIT, LOAD, DONE} states;

An enumerated type can be used as a user-defined data type, allowing the type to be used in many places.

typedef enum {FALSE, TRUE} boolean;
boolean test_complete;

7. Structures and unions

SystemVerilog adds structures to the Verilog language. Structures allow multiple variables to be grouped together under a common name. These variables can then be assigned independently, as with any variable, or the entire group can be assigned in a single statement. The declaration syntax is similar to C.

A structure definition can be given a name using typedef.

Individual members of a structure are referenced using a period between the variable name and the field name.

IR.opcode = 1; //set the opcode field in IR

All the members of a structure can also be assigned as a whole, using a list of values, as in C.

stack = {5, 200};

Structures can be assigned to structures, simplifying transferring one group of variables to another.

IR = stack;

Structures can also be passed to or from a function or task, and can be passed through module ports.

8. Arrays

Verilog data types can be declared as arrays. The reg and net types can also have a vector width declared. The arrays can have any number of dimensions. Verilog restricts access to the elements of an array to just one element at a time.

SystemVerilog refers to a Verilog array as an unpacked array. Any number of dimensions of an unpacked array can be referenced at the same time. This allows all or part of an array to be copied to another array.

r2 = r1; // copy the entire array

SystemVerilog also allows all elements of an unpacked array to be initialed to a default value with a single assignment.

r1 = {default:8’hFF}; // initialize an array

9. Module port connections

Verilog restricts the data types that can be connected to module ports. Only net types and the variable types reg, integer, or time can be passed through module ports.

SystemVerilog removes all restrictions on connections to module ports. Any data type can be passed through ports, including reals, arrays, and structures.

10. Operators

Verilog does not have the C language ++, — or assignment operators. Without these operators, code is more verbose.

for (data = 0; data <= 255; data = data + 1 )

SystemVerilog adds several new operators, including:

  • ++ and — increment and decrement operators
  • +=, -=, *=, /=, %=, &=, ^=, |=, <<=, >>=, <<<= and >>>= assignment operatorsThese operators simplify the coding of many types of operations. For example,

    for (data = 0; data <= 255; data++ )

    11. Unique and priority decision statements

    Verilog defines that if…else and case statements evaluate in source code order. In hardware implementation, this would require extra, priority encoding logic. Synthesis will optimize out this extra logic if it can determine that all branches of the decisions are mutually exclusive (unique).

    The Verilog language does not require that a decision statement always execute a branch of code. Should this occur, synthesis will add latches to the implementation.

    SystemVerilog adds the ability to specify when each branch of decision statements is unique or requires priority evaluation, using the keywords unique and priority.

    The unique and priority modifiers instruct simulators, synthesis compilers, and other tools as to the type of hardware intended. Tools can use this information to check that the code properly models the desired logic. When the priority decision modifier is specified, all tools must maintain the decision order of the source code. In addition, all tools must report an error if they detect that the decision was evaluated and no branch was executed.

    When the unique decision modifier is specified, tools can optimize out the decision order. However, all tools are required to report an error, should the tool determine that two code branches could be true at the same time. In addition, all tools must report an error if it is detected that the decision was evaluated and no branch was executed.

    12. New procedural blocks

    Verilog uses the always procedural block to represent RTL models of sequential logic, combinational logic and latched logic. Synthesis and other software tools must infer the intent of the always procedural block from the context of the statements within the procedure. This inference can lead to mismatches in simulation and synthesis results.

    SystemVerilog adds three new procedures to explicitly indicate the intent of the logic: always_ff, always_comb, and always_latch. An example of using these blocks is:

    With the intent explicitly stated, software tools can check that the procedural block functionality matches the type of procedure. Errors or warning can be generated if the code does not match the intent.

    13. Task and function enhancements

    SystemVerilog adds several enhancements to the Verilog task and function constructs. Only two of these enhancements are mentioned in this article.

    Void functions: The Verilog language requires that a function have a return value, and that function calls receive the return value.

    SystemVerilog adds a void data type, which can be specified as the return type of a function. Void functions can be called, the same as a Verilog task. The difference between a void function and a task is that functions have several restrictions, such as not allowing time controls. These restrictions help ensure that the logic in a function will synthesize correctly. By modeling with void functions instead of tasks, engineers can have greater confidence that their models will synthesize correctly.

    Function inputs and outputs: The Verilog standard requires that a function have at least one input, and that functions can only have inputs. SystemVerilog removes these restrictions. Functions can have any number of inputs, outputs and inouts, including none.

    14. Assertions

    SystemVerilog adds assertions to the Verilog standard. These assertion constructs are aligned with the PSL assertion standard, but are adapted to fit syntactically in the Verilog language.

    There are two types of assertions, immediate and sequential. Immediate assertions execute as a programming statement, similar to anif…else decision. These assertions are simple to use, and can simplify the verification and debug of even simple models. The following example asserts that at every change of state, the state value only has a single bit set.

    Sequential assertions execute in parallel with the Verilog code, and evaluate on clock cycles. A sequential assertion is described as aproperty. A property can span multiple clock cycles, which is referred to as a sequence. SystemVerilog’s PSL-like assertions can describe simple sequences and very complex sequences in short, concise sequence expressions. The example below asserts that when a request occurs, it must be followed by an acknowledge within one to three clock cycles.


    SystemVerilog is for every Verilog engineer!

    SystemVerilog provides a major set of extensions to the Verilog-2001 standard. Some of the extensions to Verilog are most useful for modeling and verifying very large designs more easily and with less coding. However, many of the SystemVerilog extensions to Verilog make it easier to model accurate, synthesizable models of any size designs. These extensions make Verilog easier to use, and are truly beneficial to every engineer that works with Verilog.


    [1]SystemVerilog for Design: A Guide to Using SystemVerilog for Hardware Design and Modeling, Stuart Sutherland, Kluwer Academic Publishers, Boston, MA, 2004, 0-4020-7530-8.
    [2]Verilog 2001: A Guide to the new Verilog Standard, Stuart Sutherland, Kluwer Academic Publishers, Boston, MA, 2001, 0- 7923-7568-8.
    [3]SystemVerilog 3.1: Accellera’s Extensions to Verilog, Accellera, Napa, CA, 2003.
    [4]IEEE Std. 1364-2001 standard for the Verilog Hardware Description Language, IEEE, Pascataway, NJ, 2001.

    Stuart Sutherland is a member of the Accellera HDL+ technical subcommittee that is defining SystemVerilog, and is the technical editor of the SystemVerilog Language Reference Manual. He is also a member of the IEEE 1364 Verilog standards group, where he serves as co-chair of the PLI task force. Sutherland is an independent Verilog consultant, and specializes in providing comprehensive expert training on the Verilog, SystemVerilog and the Verilog PLI. He can be reached by e-mail at Other papers by Stuart Sutherland are available at the Sutherland HDL web site.

    Reference :

Verilog in One Day

1. Introduction


Verilog HDL is a Hardware Description Language (HDL). A Hardware Description Language is a language used to describe a digital system, for example, a computer or a component of a computer. One may describe a digital system at several levels. For example, an HDL might describe the layout of the wires, resistors and transistors on an Integrated Circuit (IC) chip, i. e., the switch level. Or, it might describe the logical gates and flip flops in a digital system, i. e., the gate level. An even higher level describes the registers and the transfers of vectors of information between registers. This is called the Register Transfer Level (RTL). Verilog supports all of these levels. However, this handout focuses on only the portions of Verilog which support the RTL level.


1.1 What is Verilog?


Verilog is one of the two major Hardware Description Languages (HDL) used by hardware designers in industry and academia. VHDL is the other one. The industry is currently split on which is better. Many feel that Verilog is easier to learn and use than VHDL. As one hardware designer puts it, “I hope the competition uses VHDL.” VHDL was made an IEEE Standard in 1987, while Verilog is still in the IEEE standardization process. Verilog is very C-like and liked by electrical and computer engineers as most learn the C language in college. VHDL is very Ada-like and most engineers have no experience with Ada.


Verilog was introduced in 1985 by Gateway Design System Corporation, now a part of Cadence Design Systems, Inc.’s Systems Division. Until May, 1990, with the formation of Open Verilog International (OVI), Verilog HDL was a proprietary language of Cadence. Cadence was motivated to open the language to the Public Domain with the expectation that the market for Verilog HDL-related software products would grow more rapidly with broader acceptance of the language. Cadence realized that Verilog HDL users wanted other software and service companies to embrace the language and develop Verilog-supported design tools.


Verilog HDL allows a hardware designer to describe designs at a high level of abstraction such as at the architectural or behavioral level as well as the lower implementation levels (i. e. , gate and switch levels) leading to Very Large Scale Integration (VLSI) Integrated Circuits (IC) layouts and chip fabrication. A primary use of HDLs is the simulation of designs before the designer must commit to fabrication. This handout does not cover all of Verilog HDL but focuses on the use of Verilog HDL at the architectural or behavioral levels. The handout emphasizes design at the Register Transfer Level (RTL).


1.2 What is VeriWell?


VeriWell is a comprehensive implementation of Verilog HDL from Wellspring Solutions, Inc. VeriWell supports the Verilog language as specified by the OVI language Reference Manual. VeriWell was first introduced in December, 1992, and was written to be compatible with both the OVI standard and with Cadence’s Verilog-XL.


Wellspring offers free versions of their VeriWell product available from Wellspring offers free versions for DOS, Sparc and Linux. The free versions are the same as the industrial versions except they are restricted to a maximum of 1000 lines of HDL code.




1.3 Why Use Verilog HDL?


Digital systems are highly complex. At their most detailed level, they may consists of millions of elements, i. e., transistors or logic gates. Therefore, for large digital systems, gate-level design is dead. For many decades, logic schematics served as the lingua franca of logic design, but not any more. Today, hardware complexity has grown to such a degree that a schematic with logic gates is almost useless as it shows only a web of connectivity and not the functionality of design. Since the 1970s, Computer engineers and electrical engineers have moved toward hardware description languages (HDLs). The most prominent modern HDLs in industry are Verilog and VHDL. Verilog is the top HDL used by over 10,000 designers at such hardware vendors as Sun Microsystems, Apple Computer and Motorola. Industrial designers like Verilog. It works.


The Verilog language provides the digital designer with a means of describing a digital system at a wide range of levels of abstraction, and, at the same time, provides access to computer-aided design tools to aid in the design process at these levels.


Verilog allows hardware designers to express their design with behavioral constructs, deterring the details of implementation to a later stage of design in the design. An abstract representation helps the designer explore architectural alternatives through simulations and to detect design bottlenecks before detailed design begins.


Though the behavioral level of Verilog is a high level description of a digital system, it is still a precise notation. Computer aided design tools, i. e., programs, exist which will “compile” programs in the Verilog notation to the level of circuits consisting of logic gates and flip flops. One could then go to the lab and wire up the logical circuits and have a functioning system. And, other tools can “compile” programs in Verilog notation to a description of the integrated circuit masks for very large scale integration (VLSI). Therefore, with the proper automated tools, one can create a VLSI description of a design in Verilog and send the VLSI description via electronic mail to a silicon foundry in California and receive the integrated chip in a few weeks by way of snail mail. Verilog also allows the designer to specific designs at the logical gate level using gate constructs and the transistor level using switch constructs.


Our goal in the course is not to create VLSI chips but to use Verilog to precisely describe the functionality of any digital system, for example, a computer. However, a VLSI chip designed by way of Verilog’s behavioral constructs will be rather slow and be wasteful of chip area. The lower levels in Verilog allow engineers to optimize the logical circuits and VLSI layouts to maximize speed and minimize area of the VLSI chip.


2. The Verilog Language


There is no attempt in this handout to describe the complete Verilog language. It describes only the portions of the language needed to allow students to explore the architectural aspects of computers. In fact, this handout covers only a small fraction of the language. For the complete description of the Verilog HDL, consult the references at the end of the handout.


We begin our study of the Verilog language by looking at a simple Verilog program. Looking at the assignment statements, we notice that the language is very C-like. Comments have a C++ flavor, i e., they are shown by “//” to the end of the line. The Verilog language describes a digital system as a set of modules, but here we have only a single module called “simple”.


2.1 A First Verilog Program



//By Dan Hyde; August 9, 1995
//A first digital model in Verilog
module simple;
// Simple Register Transfer Level (RTL) example to demo Verilog.
// The register A is incremented by one. Then first four bits of B is
// set to "not" of the last four bits of A. C is the "and" reduction
// of the last two bits of A.
//declare registers and flip-flops
reg [0:7] A, B;
reg C;
// The two "initial"s and "always" will run concurrently
initial begin: stop_at
 // Will stop the execution after 20 simulation units.
 #20; $stop; 
// These statements done at simulation time 0 (since no #k)
initial begin: Init
 // Initialize the register A. The other registers have values of "x"
 A = 0; 
 // Display a header
 $display("Time A B C"); 
 // Prints the values anytime a value of A, B or C changes
 $monitor(" %0d %b %b %b", $time, A, B, C);
//main_process will loop until simulation is over
always begin: main_process
 // #1 means do after one unit of simulation time
 #1 A = A + 1;
 #1 B[0:3] = ~A[4:7]; // ~ is bitwise "not" operator
 #1 C = &A[6:7]; // bitwise "and" reduction of last two bits
of A

In module simple, we declared A and B as 8-bit registers and C a 1-bit register or flip-flop. Inside of the module, the one “always” and two “initial” constructs describe three threads of control, i. e., they run at the same time or concurrently. Within the initial construct, statements are executed sequentially much like in C or other traditional imperative programming languages. The always construct is the same as the initial construct except that it loops forever as long as the simulation runs.


The notation #1 means to execute the statement after delay of one unit of simulated time. Therefore, the thread of control caused by the first initial construct will delay for 20 time units before calling the system task $stop and stop the simulation.


The $display system task allows the designer to print a message much like printf does in the language C. Every time unit that one of the listed variables’ value changes, the $monitor system task prints a message. The system function $time returns the current value of simulated time.


Below is the output of the VeriWell Simulator: (See Section 3 on how to use the VeriWell simulator.)



Time A B C
 0 00000000 xxxxxxxx x
 1 00000001 xxxxxxxx x
 2 00000001 1110xxxx x
 3 00000001 1110xxxx 0
 4 00000010 1110xxxx 0
 5 00000010 1101xxxx 0
 7 00000011 1101xxxx 0
 8 00000011 1100xxxx 0
 9 00000011 1100xxxx 1
 10 00000100 1100xxxx 1
 11 00000100 1011xxxx 1
 12 00000100 1011xxxx 0
 13 00000101 1011xxxx 0
 14 00000101 1010xxxx 0
 16 00000110 1010xxxx 0
 17 00000110 1001xxxx 0
 19 00000111 1001xxxx 0
Stop at simulation time 20

You should carefully study the program and its output before going on. The structure of the program is typical of the Verilog programs you will write for this course, i. e., an initial construct to specify the length of the simulation, another initial construct to initialize registers and specify which registers to monitor and an always construct for the digital system you are modeling. Notice that all the statements in the second initial are done at time = 0, since there are no delay statements, i. e., #.


2.2 Lexical Conventions


The lexical conventions are close to the programming language C++. Comments are designated by // to the end of a line or by /* to */ across several lines. Keywords, e. g., module, are reserved and in all lower case letters. The language is case sensitive, meaning upper and lower case letters are different. Spaces are important in that they delimit tokens in the language.



Numbers are specified in the traditional form of a series of digits with or without a sign but also in the following form:


where contains decimal digits that specify the size of the constant in the number of bits. The is optional. The is the single character followed by one of the following characters b, d, o and h, which stand for binary, decimal, octal and hex, respectively. The part contains digits which are legal for the . Some examples:



  549 // decimal number
 'h 8FF // hex number
 'o765 // octal number
 4'b11 // 4-bit binary number 0011
 3'b10x // 3-bit binary number with least significant bit unknown
 5'd3 // 5-bit decimal number
 -4'b11 // 4-bit two's complement of 0011 or 1101

The part may not contain a sign. Any sign must go on the front.


A string is a sequence of characters enclosed in double quotes.



  "this is a string"

Operators are one, two or three characters and are used in expressions. See Section 2.5 for the operators.


An identifier is specified by a letter or underscore followed by zero or more letters, digits, dollar signs and underscores. Identifiers can be up to 1024 characters.


2.3 Program Structure


The Verilog language describes a digital system as a set of modules. Each of these modules has an interface to other modules to describe how they are interconnected. Usually we place one module per file but that is not a requirement. The modules may run concurrently, but usually we have one top level module which specifies a closed system containing both test data and hardware models. The top level module invokes instances of other modules.


Modules can represent bits of hardware ranging from simple gates to complete systems, e. g., a microprocessor. Modules can either be specified behaviorally or structurally (or a combination of the two). A behavioral specification defines the behavior of a digital system (module) using traditional programming language constructs, e. g., ifs, assignment statements. A structural specification expresses the behavior of a digital system (module) as a hierarchical interconnection of sub modules. At the bottom of the hierarchy the components must be primitives or specified behaviorally. Verilog primitives include gates, e. g., nand, as well as pass transistors (switches).


The structure of a module is the following:


  module  ();


The is an identifier that uniquely names the module. The is a list of input, inout and output ports which are used to connect to other modules. The section specifies data objects as registers, memories and wires as wells as procedural constructs such as functions and tasks.


The may be initial constructs, always constructs, continuous assignments or instances of modules.


Here is a behavior specification of a module NAND. The output out is the not of the and of the inputs in1 and in2.


// Behavioral Model of a Nand gate
// By Dan Hyde, August 9, 1995
module NAND(in1, in2, out);
 input in1, in2;
 output out;
 // continuous assign statement
 assign out = ~(in1 & in2);

The ports in1, in2 and out are labels on wires. The continuous assignment assign continuously watches for changes to variables in its right hand side and whenever that happens the right hand side is re-evaluated and the result immediately propagated to the left hand side (out).

The continuous assignment statement is used to model combinational circuits where the outputs change when one wiggles the input.


Here is a structural specification of a module AND obtained by connecting the output of one NAND to both inputs of another one.


module AND(in1, in2, out);
// Structural model of AND gate from two NANDS
 input in1, in2;
 output out;
 wire w1;
 // two instances of the module NAND
 NAND NAND1(in1, in2, w1);
 NAND NAND2(w1, w1, out);

This module has two instances of the NAND module called NAND1 and NAND2 connected together by an internal wire w1.


The general form to invoke an instance of a module is :



where are values of parameters passed to the instance. An example parameter passed would be the delay for a gate.

The following module is a high level module which sets some test data and sets up the monitoring of variables.


module test_AND;
// High level module to test the two other modules
 reg a, b;
 wire out1, out2;
 initial begin // Test data
 a = 0; b = 0;
 #1 a = 1; 
 #1 b = 1;
 #1 a = 0;
 initial begin // Set up monitoring
 $monitor("Time=%0d a=%b b=%b out1=%b out2=%b",
 $time, a, b, out1, out2);
 // Instances of modules AND and NAND
 AND gate1(a, b, out2);
 NAND gate2(a, b, out1);

Notice that we need to hold the values a and b over time. Therefore, we had to use 1-bit registers. reg variables store the last value that was procedurally assigned to them (just like variables in traditional imperative programming languages). wires have no storage capacity. They can be continuously driven, e. g., with a continuous assign statement or by the output of a module, or if input wires are left unconnected, they get the special value of xfor unknown.


Continuous assignments use the keyword assign whereas procedural assignments have the form = where the must be a register or memory. Procedural assignment may only appear in initial and always constructs.


The statements in the block of the first initial construct will be executed sequentially, some of which are delayed by #1, i. e., one unit of simulated time. The always construct behaves the same as the initialconstruct except that it loops forever (until the simulation stops). The initial and always constructs are used to model sequential logic (i. e., finite state automata).


Verilog makes an important distinction between procedural assignment and the continuous assignment assign . Procedural assignment changes the state of a register, i. e., sequential logic, whereas the continuous statement is used to model combinational logic. Continuous assignments drive wire variables and are evaluated and updated whenever an input operand changes value. It is important to understand and remember the difference.


We place all three modules in a file and run the simulator to produce the following output.


Time=0 a=0 b=0 out1=1 out2=0
Time=1 a=1 b=0 out1=1 out2=0
Time=2 a=1 b=1 out1=0 out2=1
Time=3 a=0 b=1 out1=1 out2=0

Since the simulator ran out of events, I didn’t need to explicit stop the simulation.


2.4 Data Types


2.4.1 Physical Data Types


Since the purpose of Verilog HDL is to model digital hardware, the primary data types are for modeling registers (reg) and wires (wire). The reg variables store the last value that was procedurally assigned to them whereas the wire variables represent physical connections between structural entities such as gates. A wire does not store a value. A wire variable is really only a label on a wire. (Note that the wire data type is only one of several net data types in Verilog HDL which include wired and (wand), wired or (wor) and tristate bus (tri). This handout is restricted to only the wire data type.)


The reg and wire data objects may have the following possible values:


  0 logical zero or false
1 logical one or true
x unknown logical value
z  high impedance of tristate gate

The reg variables are initialized to x at the start of the simulation. Any wire variable not connected to something has the xvalue.


You may specify the size of a register or wire in the declaration For example, the declarations


 reg [0:7] A, B;
 wire [0:3] Dataout;
 reg [7:0] C;

specify registers A and B to be 8-bit wide with the most significant bit the zeroth bit, whereas the most significant bit of register C is bit seven. The wire Dataoutis 4 bits wide.


The bits in a register or wire can be referenced by the notation [:].

For example, in the second procedural assignment statement


 initial begin: int1
 A = 8'b01011010;
 B = {A[0:3] | A[4:7], 4'b0000};

B is set to the first four bits of A bitwise or-ed with the last four bits of A and then concatenated with 0000. B now holds a value of 11110000. The {} brackets means the bits of the two or more arguments separated by commas are concatenated together.


The range referencing in an expression must have constant expression indices. However, a single bit may be referenced by a variable. For example:


 reg [0:7] A, B;
 B = 3;
 A[0: B] = 3'b111; // ILLEGAL - indices MUST be constant!!
 A[B] = 1'b1; // A single bit reference is LEGAL

Why such a strict requirement of constant indices in register references? Since we are describing hardware, we want only expressions which are realizable.


Memories are specified as vectors of registers. For example, Mem is 1K words each 32-bits.


  reg [31:0] Mem [0:1023];

The notation Mem[0] references the zeroth word of memory. The array index for memory (register vector) may be a register. Notice that one can notreference at the bit-level of a memory in Verilog HDL. If you want a specific range of bits in a word of memory, you must first transfer the data in the word to a temporary register.


2.4.2 Abstract Data Types


In addition to modeling hardware, there are other uses for variables in a hardware model. For example, the designer might want to use an integer variable to count the number of times an event occurs. For the convenience of the designer, Verilog HDL has several data types which do not have a corresponding hardware realization. These data types include integer, real and time. The data types integer and real behave pretty much as in other languages, e. g., C. Be warned that a reg variable is unsigned and that an integer variable is a signed 32-bit integer. This has important consequences when you subtract.


time variables hold 64-bit quantities and are used in conjunction with the $time system function. Arrays of integer and time variables (but not reals) are allowed. Multiple dimensional arrays are not allowed in Verilog HDL. Some examples:


 integer Count; // simple 32-bit integer
 integer K[1:64]; // an array of 64 integers
 time Start, Stop; // Two 64-bit time variables

2.5 Operators


2.5.1 Binary Arithmetic Operators


Binary arithmetic operators operate on two operands. Register and net (wire) operands are treated as unsigned. However, real and integer operands may be signed. If any bit is unknown (‘x‘) then result is unknown.


 Operator Name Comments   + Addition
- Subtraction
* Multiplication
/ Division Divide by zero produces an x.
% Modulus

2.5.2 Unary Arithmetic Operators


 Operator Name Comments   - Unary Minus Changes sign of its operand.

2.5.3 Relational Operators


Relational operators compare two operands and return a logical value, i. e., TRUE(1) or FALSE(0). If any bit is unknown, the relation is ambiguous and the result is unknown.

 Operator Name Comments 

> Greater than
>= Greater than or equal
< equal =”=”>

2.5.4 Logical Operators


Logical operators operate on logical operands and return a logical value, i. e., TRUE(1) or FALSE(0). Used typically in if and while statements. Do not confuse logical operators with the bitwise Boolean operators. For example , ! is a logical NOT and ~ is a bitwise NOT. The first negates, e. g., !(5 == 6) is TRUE. The second complements the bits, e. g., ~{1,0,1,1} is 0100.


 Operator Name Comments   ! Logical negation
&& Logical AND
|| Logical OR

2.5.5 Bitwise Operators


Bitwise operators operate on the bits of the operand or operands. For example, the result of A & B is the AND of each corresponding bit of A with B. Operating on an unknown (x) bit results in the expected value. For example, the AND of an x with a FALSE is an x. The OR of an x with a TRUE is a TRUE.


 Operator Name Comments   ~  Bitwise negation
&  Bitwise AND
|  Bitwise OR
^  Bitwise XOR
~&  Bitwise NAND
~|  Bitwise NOR
~^ or ^~ Equivalence Bitwise NOT XOR

2.5.6 Unary Reduction Operators


Unary reduction operators produce a single bit result from applying the operator to all of the bits of the operand. For example, &A will AND all the bits of A.


 Operator Name Comments   & AND reduction
| OR reduction
^ XOR reduction
~& NAND reduction
~| NOR reduction
~^ XNOR reduction

2.5.7 Other Operators

The conditional operator operates much like in the language C.


Operator Name Comments 
=== Case equality The bitwise comparison includes comparison of x and z
                  values.  All bits must match for equality.  Returns TRUE
                  or FALSE.
!== Case inequality The bitwise comparison includes comparison of x and z
                  values.  Any bit difference produces inequality.  Returns
                  TRUE or FALSE.
{ , } Concatenation Joins bits together with 2 or more comma-separated expressions,
                  e, g. {A[0], B[1:7]} concatenates the zeroth bit of A to
                  bits 1 to 7 of B.
<<>A = A <<> shifts A two bits to left with zero fill.
>> Shift right Vacated bit positions are filled with zeros.
?: Conditional Assigns one of two values depending on the conditional
                  expression.  E. g., A = C>D ? B+3 : B-2  means
                  if C greater than D, the value of A is B+3 otherwise B-2.

2.5.8 Operator Precedence


The precedence of operators is shown below. The top of the table is the highest precedence and the bottom is the lowest. Operators on the same line have the same precedence and associate left to right in an expression. Parentheses can be used to change the precedence or clarify the situation. We strongly urge you to use parentheses to improve readability.


unary operators: ! & ~& | ~| ^ ~^ + -  (highest precedence)
* / %
+ -
<< >>
< <= > >+
== != === ~==
& ~&amp;amp;amp;amp;amp;amp; ^ ~^
| ~|

2.6 Control Constructs


Verilog HDL has a rich collection of control statements which can used in the procedural sections of code, i. e., within an initial or always block. Most of them will be familiar to the programmer of traditional programming languages like C. The main difference is instead of C’s { } brackets, Verilog HDL uses begin and end. In Verilog, the { } brackets are used for concatenation of bit strings. Since most users are familiar with C, the following subsections typically show only an example of each construct.


2.6.1 Selection – if and case Statements


The if statement is easy to use.


 if (A == 4)
 B = 2;
 B = 4;

Unlike the case statement in C, the first that matches the value of the is selected and the associated statement is executed then control is transferred to after the endcase, i. e., no break statements are needed as in C.


 case ()

The following example checks a 1-bit signal for its value.


 case (sig)
 1'bz: $display("Signal is floating");
 1'bx: $display("Signal is unknown");
 default: $display("Signal is %b", sig);

2.6.2 Repetition – for, while and repeat Statements


The for statement is very close to C’s for statement except that the ++ and — operators do not exist in Verilog. Therefore, we need to use i = i + 1.


 for(i = 0; i < i =" i">
 $display("i= %0d", i);

The while statement acts in the normal fashion.


 i = 0;
 while(i <>
 $display("i= %0d", i);
 i = i + 1;

The repeat statement repeats the following block a fixed number of times, in this example, five times.


 repeat (5)
 $display("i= %0d", i);
 i = i + 1;

2.7 Other Statements


2.7.1 parameter Statement


The parameter statement allows the designer to give a constant a name. Typical uses are to specify width of registers and delays. For example, the following allows the designer to parameterized the declarations of a model.


 parameter byte_size = 8;
 reg [byte_size - 1:0] A, B; 

2.7.2 Continuous Assignment


Continuous assignments drive wire variables and are evaluated and updated whenever an input operand changes value. The following ands the values on the wires in1 and in2 and drives the wire out. The keyword assign is used to distinguish the continuous assignment from the procedural assignment. See Section 2.3 for more discussion on continuous assignment.


 assign out = ~(in1 & in2); 

2.7.3 Blocking and Non-blocking Procedural Assignments


The Verilog language has two forms of the procedural assignment statement: blocking and non-blocking. The two are distinguished by the = and <= assignment operators. The blocking assignment statement (= operator) acts much like in traditional programming languages. The whole statement is done before control passes on to the next statement. The non-blocking (<= operator) evaluates all the right-hand sides for the current time unit and assigns the left-hand sides at the end of the time unit. For example, the following Verilog program


// testing blocking and non-blocking assignment
module blocking;
reg [0:7] A, B;
initial begin: init1
 A = 3;
 #1 A = A + 1; // blocking procedural assignment
 B = A + 1;
 $display("Blocking: A= %b B= %b", A, B );
 A = 3;
 #1 A <= A + 1; // non-blocking procedural assignment
 B <= A + 1;
 #1 $display("Non-blocking: A= %b B= %b", A, B ); 

produces the following output:


Blocking: A= 00000100 B= 00000101
Non-blocking: A= 00000100 B= 00000100 

The effect is for all the non-blocking assignments to use the old values of the variables at the beginning of the current time unit and to assign the registers new values at the end of the current time unit. This reflects how register transfers occur in some hardware systems.


2.8 Tasks and Functions


Tasks are like procedures in other programming languages, e. g., tasks may have zero or more arguments and do not return a value. Functions act like function subprograms in other languages. Except:


1. A Verilog function must execute during one simulation time unit. That is, no time controlling statements, i. e., no delay control (#), no event control (@) or wait statements, allowed. A task can contain time controlled statements.


2. A Verilog function can not invoke (call, enable) a task; whereas a task may call other tasks and functions.


The definition of a task is the following:


 task ; // Notice: no list inside ()s 

An invocation of a task is of the following form:



where is a list of expressions which correspond to the of the definition. Port arguments in the definition may be input, inout or output. Since the in the task definition look like declarations, the programmer must be careful in adding declares at the beginning of a task.


// Testing tasks and functions
// Dan Hyde, Aug 28, 1995
module tasks;
task add; // task definition
 input a, b; // two input argument ports
 output c; // one output argument port
 reg R; // register declaration
 R = 1;
 if (a == b)
 c = 1 & R;
 c = 0;
initial begin: init1
 reg p;
 add(1, 0, p); // invocation of task with 3 arguments
 $display("p= %b", p); 

input and inout parameters are passed by value to the task and output and inout parameters are passed back to invocation by value on return. Call by reference is not available.


Allocation of all variables is static. Therefore, a task may call itself but each invocation of the task uses the same storage, i. e., the local variables are not pushed on a stack. Since concurrent threads may invoke the same task, the programmer must be aware of the static nature of storage and avoid unwanted overwriting of shared storage space.


The purpose of a function is to return a value that is to be used in an expression. A function definition must contain at least one input argument. The passing of arguments in functions is the same as with tasks (see above). The definition of a function is the following:


 function ; // Notice: no list inside ()s 


where is the type of the results passed back to the expression where the function was called. Inside the function, one must assign the function name a value. Below is a function which is similar to the task above.


// Testing functions
// Dan Hyde, Aug 28, 1995
module functions;
function [1:1] add2; // function definition
 input a, b; // two input argument ports
 reg R; // register declaration
 R = 1;
 if (a == b)
 add2 = 1 & R;
 add2 = 0;
initial begin: init1
 reg p;
 p = add2(1, 0); // invocation of function with 2 arguments
 $display("p= %b", p); 

2.9 Timing Control


The Verilog language provides two types of explicit timing control over when simulation time procedural statements are to occur. The first type is a delay control in which an expression specifies the time duration between initially encountering the statement and when the statement actually executes. The second type of timing control is the event expression, which allows statement execution. The third subsection describes the wait statement which waits for a specific variable to change.


Verilog is a discrete event time simulator, i. e., events are scheduled for discrete times and placed on an ordered-by-time wait queue. The earliest events are at the front of the wait queue and the later events are behind them. The simulator removes all the events for the current simulation time and processes them. During the processing, more events may be created and placed in the proper place in the queue for later processing. When all the events of the current time have been processed, the simulator advances time and processes the next events at the front of the queue.


If there is no timing control, simulation time does not advance. Simulated time can only progress by one of the following:


 1. gate or wire delay, if specified.

2. a delay control, introduced by the # symbol.

3. an event control, introduced by the @ symbol.

4. the wait statement.

The order of execution of events in the same clock time may not be predictable.



2.9.1 Delay Control ( #)

A delay control expression specifies the time duration between initially encountering the statement and when the statement actually executes. For example:


 #10 A = A + 1;

specifies to delay 10 time units before executing the procedural assignment statement. The # may be followed by an expression with variables.


2.9.2 Events


The execution of a procedural statement can be triggered with a value change on a wire or register, or the occurrence of a named event. Some examples:


 @r begin // controlled by any value change in 
 A = B&C; // the register r
 @(posedge clock2) A = B&C; // controlled by positive edge of clock2
 @(negedge clock3) A = B&C; // controlled by negative edge of clock3
 forever @(negedge clock) // controlled by negative edge
 A = B&C;

In the forms using posedge and negedge, they must be followed by a 1-bit expression, typically a clock. A negedge is detected on the transition from 1 to 0 (or unknown). A posedge is detected on the transition from 0 to 1 (or unknown).


Verilog also provides features to name an event and then to trigger the occurrence of that event. We must first declare the event:


 event event6; 

To trigger the event, we use the -> symbol :


 -> event6; 

To control a block of code, we use the @ symbol as shown:


 @(event6) begin

We assume that the event occurs in one thread of control, i. e., concurrently, and the controlled code is in another thread. Several events may to or-ed inside the parentheses.


2.9.3 Wait Statement


The wait statement allows a procedural statement or a block to be delayed until a condition becomes true.


 wait (A == 3)
 A = B&C;

The difference between the behavior of a wait statement and an event is that the wait statement is level sensitive whereas @(posedge clock); is triggered by a signal transition or is edge sensitive.


2.10 Traffic Light Example


To demonstrate tasks as well as events, we will show a hardware model of a traffic light.


// Digital model of a traffic light
// By Dan Hyde August 10, 1995
module traffic;
parameter on = 1, off = 0, red_tics = 35, 
 amber_tics = 3, green_tics = 20;
reg clock, red, amber, green;
// will stop the simulation after 1000 time units
initial begin: stop_at
 #1000; $stop; 
// initialize the lights and set up monitoring of registers
initial begin: Init
 red = off; amber = off; green = off;
 $display(" Time green amber red"); 
 $monitor("%3d %b %b %b", $time, green, amber, red);
// task to wait for 'tics' positive edge clocks
// before turning light off
task light;
 output color;
 input [31:0] tics;
 repeat(tics) // wait to detect tics positive edges on clock
 @(posedge clock);
 color = off;
// waveform for clock period of 2 time units
always begin: clock_wave
 #1 clock = 0;
 #1 clock = 1;
always begin: main_process
 red = on;
 light(red, red_tics); // call task to wait 
 green = on;
 light(green, green_tics);
 amber = on;
 light(amber, amber_tics);

The output of the traffic light simulator is the following:


 Time green amber red
 0 0 0 1
 70 1 0 0
 110 0 1 0
 116 0 0 1
 186 1 0 0
 226 0 1 0
 232 0 0 1
 302 1 0 0
 342 0 1 0
 348 0 0 1
 418 1 0 0
 458 0 1 0
 464 0 0 1
 534 1 0 0
 574 0 1 0
 580 0 0 1
 650 1 0 0
 690 0 1 0
 696 0 0 1
 766 1 0 0
 806 0 1 0
 812 0 0 1
 882 1 0 0
 922 0 1 0
 928 0 0 1
 998 1 0 0
Stop at simulation time 1000 

Verilog Free Simulator and Viewer

Icarus Verilog : This is best Free Verilog simulator out there, it is simulation and synthesis tool. It operates as a compiler, compiling source code written in Verilog (IEEE-1364) into some target format. For batch simulation, the compiler can generate an intermediate form called vvp assembly. This intermediate form is executed by the “vvp” command. Icarus continues to get better and better. Icarus is being used for real design work by companies now as a simulator, and is starting to be useful as a synthesizer for a Xilinx FPGA flow as well.
Dinotrace : Freeware VCD viewer from veritools

I have tested above combination on linux. Both works fine…and is good to start with.

Sample Design:
module encoder_using_if(
binary_out , // 4 bit binary output
encoder_in , // 16-bit input
enable // Enable for the encoder
//———–Output Ports—————
output [3:0] binary_out ;
//———–Input Ports—————
input enable ;
input [15:0] encoder_in ;
//————Internal Variables——–
reg [3:0] binary_out ;
//————-Code Start—————–
always @ (enable or encoder_in)
binary_out = 0;
if (enable) begin
if (encoder_in == 16’h0002) begin
binary_out = 1;
end if (encoder_in == 16’h0004) begin
binary_out = 2;
end if (encoder_in == 16’h0008) begin
binary_out = 3;
end if (encoder_in == 16’h0010) begin
binary_out = 4;
end if (encoder_in == 16’h0020) begin
binary_out = 5;
end if (encoder_in == 16’h0040) begin
binary_out = 6;
end if (encoder_in == 16’h0080) begin
binary_out = 7;
end if (encoder_in == 16’h0100) begin
binary_out = 8;
end if (encoder_in == 16’h0200) begin
binary_out = 9;
end if (encoder_in == 16’h0400) begin
binary_out = 10;
end if (encoder_in == 16’h0800) begin
binary_out = 11;
end if (encoder_in == 16’h1000) begin
binary_out = 12;
end if (encoder_in == 16’h2000) begin
binary_out = 13;
end if (encoder_in == 16’h4000) begin
binary_out = 14;
end if (encoder_in == 16’h8000) begin
binary_out = 15;

`timescale 1ns/1ps
`include “encoder_using_if.v”
module encoder_test;
wire [3:0] binary_out;
reg enable;
reg [15:0] encoder_in;

encoder_using_if encode(.binary_out (binary_out), .encoder_in (encoder_in) , .enable (enable));

initial begin
#1 enable = 0;
encoder_in = 16’h0;

#2 enable = 1;
encoder_in = 16’h0001;

encoder_in = 16’h0010;
#1 $finish;
initial begin
$monitor(“Encoder out = %h \n”,binary_out);
//always @ (enable or encoder_in)
$dumpfile( “foo.vcd” );
$dumpvars( 0, encoder_test );

Command Used:

iverilog testbench.v
./dinotrace foo.vcd

Keywords: Verilog, free simulator, waveform viewer, Icarus Verilog, Dinotrace