Debugging Programs

A helpful framework for debugging Verilog programs.

The 'best' way to debug a Verilog program is by writing a testbench and plodding through the simulatated waveforms. However, it is often worthwhile to check for some common mistakes first. Here are a few that I found useful to look out for.

These have been divided into general Verilog programming errors, and some specific to the FPGA setup used in EECS 270.

General Errors

Objects/nets are Incorrectly Sized

If the hardware structures you are using do not have enough bits to store all the information you want them to, that can cause issues.

For example, if your state machine has 4 states, but you only have a 1 bit state register (reg state), you’re likely to run into trouble when you enter states 2 and beyond (state <= 2 will overflow).

This also occurs when you do not specify sizes for a reg or wire (or explicitly declare a wire)—its size defaults to 1 without warning.

parameter ready  = 2'b0
parameter steady = 2'b1
parameter go     = 2'b2
parameter stop   = 2'b3

reg        state;
reg [1:0]  State;

wire [1:0] Next_State;

always@(posedge clock) begin 
    // this assignment will overflow
    state = go;
    // this assignment will not
    State = go;
end

// This assignment will implicitly declare a 1-bit wire and overflow
assign next_state = Stop;
// This will not overflow, as the 2-bit wire bus has been declared
assign Next_state = Stop;

Ensure Port Widths Match Connections

Mismatched Port widths can lead to errors. Sometimes these are only listed as warnings by the compiler, be on the lookout for those!

Ensure Correct Port Connections when Instantiating Modules

Verilog compilers can be very lenient at times. For example, the following code may not even trigger a warning:

module MAJ(a, b, c, m);
    input a, b, c;
    output m;

    and a1(ab, a, b);
    and a2(ac, a, c);
    and a3(bc, b, c);
    or o(m, ab, ac, bc);
endmodule


module Testbench();
    reg a;
    reg b;
    reg c;
    wire m;
    // there is no connection for port c!
    MAJ m (.a(a),
        .b(b),
        .m(m));
endmodule

This should be checked for, especially for modules with many ports.

Check For Latches

Compilers usually point out when a latch is created, sometimes as warnings. Usually, they are undesirable, as they are level sensitive and prone to glitches caused by race conditions.

In Verilog, latches are often created unintentionally in behavioral models (using always blocks) when not all outputs are specified for every possible input condition. This is a common pitfall, especially when writing combinational logic.

For instance, if an always block meant for combinational logic does not assign a value to a register in one of the branches of an if statement, synthesis tools may infer a latch to hold the value of the register when the condition is not met.

reg [3:0] countdown;

always@(*) begin 
    case(state) begin
        A: begin 
            if (reset) begin 
                countdown = 6;
            end
        end
        B: begin 
            countdown = 7;
        end
    end
end

In the above block, countdown isn't assigned any value in state A when reset isn't true. Hence, the synthesiser would likely create a latch. This can cause issues as it may hold onto its previous value whenever reset is false, even when in a state B. Not fun.

EECS 270 Specific Errors

Ensure Correct Top Level Module

When compiling and synthesising code, Quartus Prime links the top level module to the FPGA board. If that hasn’t been set correctly, your code won’t interface with the board as you’d like.

Check the hierarchy/files dropdown near the top left of the Quartus Prime window to confirm.

Also confirm whether all the correct files have been added to your project by examining the ‘files’ dropdown.

Ensure the FPGA works

What better way to ruin one's day than a 3-hour battle with a faulty FPGA board. Double check your program by uploading it to LabsLand!

Last updated