Yet Another Verilog Tutorial

Introduction

While studying Boolean algebra, for example when simplifying Boolean expressions, you may want to check your answer. One way to do this is to generate the truth table for the original expression and your simplified expression, and then check that they're the same. There are tools online that can help you do that. Another way is through computer programming. You could write a short program in your favorite programming language with both expressions, and then see that they output the same result for all possible combinations of the input variables. Yet another way is to use a hardware description language (HDL). An HDL is a specialized computer language that you can use to describe digital logic circuits, which in turn are described by Boolean expressions. In this tutorial, we will be using the Verilog HDL. (This tutorial is heavily based on Jose Vargas's Getting started with Icarus Verilog on Windows, which is cited in the References section below. Some basic programming knowledge is recommended before proceeding.)

Icarus Verilog

A program written in an HDL like Verilog is a description of a hardware system. HDL programs will be referred to as descriptions from this point forward. Unlike programs in typical programming languages, after the program is compiled, HDL descriptions are simulated instead of executed. Simulation executes a simulation model, which is generated by the compiler from the description. We will need an HDL simulator to compile and simulate HDL descriptions. There are many HDL simulators available. If you're running Windows, one free and open-source simulator that is available is Icarus Verilog (it runs on Macs and Linux as well).

Writing a simple program

Once you have downloaded and installed Icarus Verilog, you are ready to write your first Verilog description. We will be writing a hardware description of a basic 2-input AND gate. The output of an AND gate is 1 if and only if all of its inputs are also 1. Here is its truth table:

INPUT OUTPUT
A B A AND B
0 0 0
0 1 0
1 0 0
1 1 1

Our first description is basic_and.v. Here is its code:
    module basic_and (a, b, out);
      input a, b;
      output out;
   
      assign out = a & b;
    endmodule

    module basic_and_tb();
      reg a, b;
      wire out;
   
      basic_and DUT (
        .a(a),
        .b(b),
        .out(out)
      );
   
      initial begin
        // Dump results of the simulation to basic_and.vcd
        $dumpfile("basic_and.vcd");
        $dumpvars;

        a = 0;
        b = 0;
        #20
        a = 0;
        b = 1;
        #20
        a = 1;
        b = 0;
        #20
        a = 1;
        b = 1;
        #20
        $finish;
      end
    endmodule
    
If you look at the above description, notice that it is composed of two modules, each of which starts with the keyword module and ends with the keyword endmodule. The fundamental descriptive unit in Verilog is the module, and a Verilog description is separated into different modules. You could think of them as rough equivalents of functions in other programming languages. The first module above, called basic_and, is a description of our basic AND gate. The second module, called basic_and_tb, is what is known as a test bench, which is HDL code that allows you to provide a documented, repeatable set of stimuli that is portable across different simulators. To simulate our design, we will need both the Device Under Test (DUT), which in this case is our AND gate described in basic_and, and the stimulus provided by the test bench.

The lines that start with module are declarations. The declaration states the module's name, and inside the parentheses are its inputs and outputs. You can see that inside the module, we declare which variables are inputs and outputs using the keywords input and output, respectively. The assign keyword assigns out to be inputs a and b ANDed together using the operator &. (Notice that commas (,) are used to separate elements of a list, and semicolons (;) are used to terminate Verilog statements. If you know any C-like languages, this should be very familiar.)

Let's look at basic_and_tb next. First, notice that the module declaration does not have any input or output ports. The rest of the module can be divided into three parts: (1) declaration, (2) instantiation, and (3) simulation:
  1. Declaration: The inputs to the circuit are declared with keyword reg and the outputs are declared with the keyword wire. (For more information on the differences between wire and reg, take a look at Verilog: wire vs. reg.)
  2. Instantation: In the line that starts with basic_and DUT, we instantiate our basic_and module. This is the same instantiation that happens in object-oriented programming. When we instantiate a module, Verilog creates a unique object from the module, and the objects are called instances. DUT is the name given to this instance. You don't have to name the instance DUT -- you can give it a different name, if you like, but every instantiation of a module needs a unique instance name. Furthermore, this instantiation is an example of module port mapping by name. For each module input and output, we need to indicate which reg or wire in our test bench is connected to it. A name following a '.' corresponds to a name given in the module declaration, while a name inside parentheses corresponds to the name of a reg or wire in our test bench. In this example, they happen to be the same. If you have ever tested actual hardware before, instantiation is like attaching signal generators to the inputs of a circuit and probes to the outputs of the circuit.
  3. Simulation: Here we specify exactly what happens during our simulation. This section starts with the keyword initial and is followed by a set of statements, enclosed by the keywords begin and end, that begin executing when the simulation is initialized. The $dumpfile and $dumpvars are commands that tell the Verilog simulator to log the module's variables to the file specified. Next, we assign values (0 initially) to the inputs of the DUT, a and b. Lines that start with '#' specify a delay in the simulation given in seconds (s). So after 20 s, input b changes to 1. Note that regs retain their values after they are assigned, so the a=0; immediately after #20 could have been omitted. Continuing in this fashion, we are specifying the input waveforms to be every possible combination of inputs a and b for a period of 20 s. Finally, the $finish system task explicitly tells the simulator to stop the simulation.

Compiling and simulating

The following instructions are specific to Windows, but the procedure is not that different on Macs and Linux:
        iverilog -o basic_and basic_and.v

      iverilog is the name of the Icarus Verilog compiler. The "-o" specifies the name of the output file. If no output file name is specified, iverilog uses the default name a.out. (If you know C/C++, this is the same thing that happens if you don't specify "-o" to gcc or g++.)
        vvp basic_and

      vvp stands for Verilog Virtual Processor. It is the run time engine that executes the default compiled form generated by Icarus Verilog. It's what outputs the basic_and.vcd file with all the simulation results. (In case you are wondering what VCD is, it's an industry standard simulation dump format.)

Next, we will need a tool to visualize the simulation results. GTKWave is such a tool that comes with the Windows version of Icarus Verilog.
We've opened the file, but we don't see any waveforms yet. If we want to see a timing diagram, we need to specify which variables we want to see the timing diagrams for.
If all goes well, you should get a timing diagram just like the following:

GTKWave Waveform

Compare this timing diagram with the truth table given earlier. Notice that waveform of out, the output of the AND gate, is always low (or 0) until time = 60 s to time = 80 s, when it's high (or 1). That's the only time that both inputs a and b are 1. So our waveform bears out what the truth table says the output of an AND gate should be.

This was just a very simple example designed to serve as a brief introduction to Verilog. This is just the tip of the iceberg of what Verilog can do. If you want to learn more, take a look at the references below, and start creating Verilog descriptions of your own!

References

Back to homepage.