Table of Contents

FPGA Verilog simulation using GTKWave on the iCE40-feather

One of the nice things about working with FPGAs and Verilog is the array of open source tools and development boards that are available.

For this article I'll be using the iCE40-feather development board by Josh Johnson which is based on the Lattice iCE40 UltraPlus Breakout Board, but the simulation set up should be the same for many boards.

If you are using an iCE40-feather, you can follow the set up instructions to get the icestorm toolchain installed, and get drivers working for this FTDI based board.

Our aim is to take a verilog file, a testbench and simulate it using Icarus Verilog / GTKWave.

Setting up a project

We'll start with a simple standard blinker in one file.

Create a folder called:

simple-blink

Create a verilog file inside the folder and call it blink.v:

`default_nettype none
 
module top #(parameter integer DELAY = 2500000) (
    input wire clk,
    output wire nLED_GRN
    );
 
  reg [31:0] r_MAX = DELAY;
  reg [31:0] r_COUNT = 0;
 
  reg r_led = 0;
 
  always @ (posedge clk)
  begin
    if (r_COUNT < r_MAX)
      begin
        r_COUNT <= r_COUNT + 1;
      end
    else
      begin
        r_COUNT <= 0;
        r_led <= !r_led;
      end
  end
 
  assign nLED_GRN = r_led;
 
endmodule

Nice and simple, blink the green LED on the iCE40-feather board after several thousand clock cycles.

Now a testbench file, create a blink_tb.v file in our project folder:

`timescale 1ns/1ns
`include "blink.v"
 
module blink_tb;
 
  reg tClk = 1'b0;
  wire tLed;
 
  top #(
    .DELAY(10)
  ) UUT
  (
    .clk(tClk),
    .nLED_GRN(tLed)
  );
 
  always #2 tClk <= !tClk;
 
  // Dump wave
  initial 
    begin
      $dumpfile("blink_tb.lxt");
      $dumpvars(0,blink_tb);
    end
 
  initial
    begin
      #100;
      $finish;
    end
 
endmodule

I'll explain a couple of things from the testbench. Firstly, an ns timescale is being used. So each time unit is a nanosecond. This will keep the timescale nice and compressed to view in the simulation. In the real module, the timescale has too much data to comfortably view.

There is a dump file generated using the testbench. Icarus Verilog / GTKWave uses these files for its simulation.

Now to download and install Icarus Verilog / GTKWave from: http://bleyer.org/icarus

Open a commandline to the project folder. We'll execute all the steps manually. And later, we'll move them to a Makefile to make life much easier.

Manual Simulation Steps

Create a sim folder with:

  mkdir sim

Next…

  iverilog -Wall -o sim/blink_tb blink_tb.v

This will compile the testbench into code suitable for simulation by the vvp runtime.

  vvp sim/blink_tb -lxt2

vvp takes the compiled blink_tb and executes a simulation with it. The -lxt2 flag means to output an lxt2 dump file that the GTKWave is able to nicely display for us.

  mv blink_tb.lxt sim/blink_tb.lxt

Simply move the resulting blink_tb.lxt file into the sim folder.

  gtkwave sim/blink_tb.lxt

Here's the exciting bit. GTKWave will open up and load the simulation dump. But as yet, no signals have been chosen to visualise:

Drag the clk[0] and nLED_GRN[0] signals into the Waves pane and your waveforms will display!

The wave setup is lost if you exit GTKWave. But you can save a config so that these signals are chosen next time you recompile the code. Select File > Write Save File As.

Save the file into the sim folder as: gtkwaveConfig.gtkw

Now close GTKWave. If we change the gtkwave command next time to:

  gtkwave sim/blink_tb.lxt sim/gtkwaveConfig.gtkw

…the signals you set previously will be shown again.

Automatic Simulation Steps with a Makefile

It would be cumbersome to type all those commands each time you made a change to your verilog code to display your simulation. Thankfully a makefile can make like so much easier.

You can pinch a really nice one from Josh Johnson's version of the WTFpga course.

The main piece of interest from the makefile is this:

simulate:
	iverilog -Wall -o sim/$(PROJ)_tb $(PROJ)_tb.v
	vvp sim/$(PROJ)_tb -lxt2
	mv $(PROJ)_tb.lxt sim/$(PROJ)_tb.lxt
	gtkwave sim/$(PROJ)_tb.lxt sim/gtkwaveConfig.gtkw

Copy the Makefile into the root of your project folder.

Now you can execute everything and see your simulation in one step with:

  make simulate

And that's it. Enjoy!