====== 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 [[https://github.com/joshajohnson/iCE40-feather|iCE40-feather]] development board by Josh Johnson which is based on the [[http://www.latticesemi.com/-/media/LatticeSemi/Documents/UserManuals/EI/FPGAUG0200110.ashx?document_id=51987|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 [[https://github.com/joshajohnson/WTFpga/blob/master/install.md|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: {{ :wiki:gtkwave-loaded.png?nolink |}} Drag the ''clk[0]'' and ''nLED_GRN[0]'' signals into the ''Waves'' pane and your waveforms will display! {{ :wiki:gtkwave-with-signals.png?nolink |}} 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''. {{ :wiki:gtkwave-save-config.png?nolink |}} 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 [[https://github.com/joshajohnson/WTFpga/blob/master/blink/Makefile|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!