Starting Verilog

This is a record of my attempts to learn enough Verilog to design and simulate a simple but complete CPU to include in my electronics textbook. To guide my steps I am relying the book Verilog Digital System Design by Zainalabedin Navabi. I will comment a little on the Verilog language at least at the beginning but will not attempt to cover the language in any real detail. For that Navabi's book is excellent.

I start with the need for a Verilog system that will work on a Mac. I have found a version called Icarus Verilog that is freely available at this website

verilog.icarus.com

The system consists of two programs; iverilog reads a set of text files (.v files) in the Verilog language and compiles them into an executable for a special virtual machine, vvp then executes the resulting program and generates the output. At its simplest the output is the results of text output commands in the test program. For more complex cases it generates compressed outputs that can be studied with a third program, gtkwave.

Installing Verilog

I followed the OSX instructions on the icarus wiki at

iverilog.wikia.com/wiki/Installation_Guide

except that I used the command

sudo port -v install iverilog

since the gtkwave install (which I tried first) did not include iverilog.

NOTE that this all worked easily because I already had MacPorts installed. Otherwise I would have had to go through the (easy) process of installing MacPorts first.

Once I waited through the installs I was able to run the "iverilog" and "vvd" commands at any command prompt.

My First Verilog Program

To test the system I started with the simple 3-bit counter from Navabi's book. Here is the actual counter code.

Counter.v
module counter(out, clk, reset);
 parameter WIDTH = 8;
 output [WIDTH-1 : 0] out;
 input clk, reset;
 reg [WIDTH-1 : 0]   out;
 wire clk, reset;
 always @(posedge clk)
    out <= out + 1;
 always @reset
    if (reset)
       assign out = 0;
    else
       deassign out;
endmodule // counter

The module is the basic structural element of Verilog. This is a "dataflow" description of an adjustable width, positive edge-triggered, binary up-counter. It has two inputs, a clock and an asynchronous reset, and a variable width output. It demonstrates various features of Verilog.

The module line does three things. It tells us that this is the start of a new self-contained Verilog object (a module) and that the module is generically called 'counter'. Then it tells us that a counter has three connections to the outside, named out, clk, and reset. As usual, the names are completely arbitrary but it is good practice to use names that will make sense to the reader. At this point we know nothing about these connections.

The first line after the module declaration introduces a named constant that can be used anywhere a number is needed. Here it is used to make it easy to alter the bit-width of the counter. With 8 bits, as shown, the counter can count from 0 to 255.

The next pair of lines start to explain the connections. The first tells us that the signal 'out' is an output from the module and that it is 'width' bits wide, in this case 8. Note that the width property comes BEFORE the signal name in Verilog. The second line tells us that 'clk' and 'reset' are inputs to the module and, by inference, that they are single-bit values.

The next pair add more information. 'out' is a 'registered' variable. That is, it holds its value even after the input that has caused it is removed. The inputs, however, are declared to be wires. These are tri-state objects that can be in any of four states, undefined (x), 0, 1, and high-impedance (z). A wire has the undefined state before anything has driven it. Once driven its output state will be determined by its inputs.

By itself, the Counter.v program is only a component of a larger program, like a subroutine in normal programming. A complete program will need some sort of driver, a main program to call the subroutine. Following the naming scheme in Navabi's book, I have the test program

module test;
 /* Make a reset that pulses twice. */
         reg reset = 0;
         initial begin
         # 17 reset = 1;
         # 11 reset = 0;
         # 14 reset = 1;		// Note that at cumulative time 17+11+14=42
         # 11 reset = 0; 
         # 200 $stop;
         end
 /* Make a regular pulsing clock. */
         reg clk = 0;
         always #5 clk = !clk;
 wire [7:0] value;
         counter c1 (value, clk, reset);
 initial
         $monitor("At time %t, value = %h (%0d)",
         $time, value, value);
endmodule // test

This time we see a module without inputs or outputs. Instead we have three kinds of body. The two sections that begin with C-style block comments define signals (using names that are known only to this file--they have no intrinsic connection to the similarly named signals in counter.v) and specify their values for the life of the simulation. The lines that begin with a '#' specify times at which things happen. They are a little odd in that you specify not the actual time at which an event occurs but the time interval from the previous event. Thus the reset signal goes high for the second time in the line

# 14 reset = 1;

This event takes place 14 time units after the previous event and thus 42 intervals (see the comment) after the simulation starts.

The third section decares an 8-bit output named 'value' that it connects to the output of a counter (named 'c1') whose inputs are connected to the clk and reset signals. Note again that, although these files use the same names for the clk and reset signal in both the test program and the subroutine that is by no means required. The actual connection is all by position in the argument list to the counter. Indeed we use the completely different names 'out' and 'value' for the output signals in the two places.

The final section sets up some debugging output using the command $monitor. This is different from all the previous text. Up till now everything has been describing the hardware and its running. This is a request to the runtime system to log various values to standard output as the simulation runs. It tells the runtime what to output but does not alter the structure or running of the simulation.

We first compile these text sources into an executable program with the command

iverilog -o my_design  counter_tb.v counter.v

which, if all is well, produces no output. We then execute the my_design program using vvp

vvp my_design

which produces the output

At time                    0, value = xx (x)
At time                   17, value = 00 (0)
At time                   35, value = 01 (1)
At time                   42, value = 00 (0)
At time                   55, value = 01 (1)
At time                   65, value = 02 (2)
At time                   75, value = 03 (3)
At time                   85, value = 04 (4)
At time                   95, value = 05 (5)
At time                  105, value = 06 (6)
At time                  115, value = 07 (7)
At time                  125, value = 08 (8)
At time                  135, value = 09 (9)
At time                  145, value = 0a (10)
At time                  155, value = 0b (11)
At time                  165, value = 0c (12)
At time                  175, value = 0d (13)
At time                  185, value = 0e (14)
At time                  195, value = 0f (15)
At time                  205, value = 10 (16)
At time                  215, value = 11 (17)
At time                  225, value = 12 (18)
At time                  235, value = 13 (19)
At time                  245, value = 14 (20)
** VVP Stop(0) **
** Flushing output streams.
** Current simulation time is 253 ticks.
> 

We see that in the beginning value was undefined but then the reset signal activated at time 17 (see the line # 17 in the test) and the value went to 00. It started to count up but was interrupted by the second reset (at time 42, the sum of the time intervals preceeding the reset command). Then it ran happily incrementing every clock until we stopped the simulation at time 245. Note that the output is only recorded when something changes on the inputs and so almost all the events are recorded at the rising edges of the clock, every 10 time units.

Because I cribbed this example pretty much straight from the book it worked with only minor correction needed for silly typos.

 

Brian Collett