Opensource FPGA: First Steps with the IceStorm Toolchain

This blog post gets you started with Project IceStorm, a fully open source Verilog-to-Bitstream flow for iCE40 FPGAs. First we will cover installation of the toolchain on Linux and Mac OS X. Then a simple blinky program is synthesized, routed and programmed on a Lattice iCEStick. At the end some

This blog post gets you started with Project IceStorm, a fully open source Verilog-to-Bitstream flow for iCE40 FPGAs. First we will cover installation of the toolchain on Linux and Mac OS X. Then a simple blinky program is synthesized, routed and programmed on a Lattice iCEStick. At the end some further resources are collected.

Work in progress!

Overview

FPGA stands for "Field Programmable Gate Array", it is essentially a huge array of logic gates which can be arbitrarily connected to make a circuit of your choice.



flow

Installation

Four tools need to be installed:

  1. yosys: Verilog RTL synthesis
  2. Icarus Verilog: Verilog simulation and synthesis tool
    • iverilog: The compiler
    • vvp: Simulation runtime engine
  3. arachne-pnr: Place and route tool for FPGAs
  4. icestorm: Tools for generating and manipulating iCE40 bitstreams
    • icebox
    • icebram
    • icecompr
    • icefuzz
    • icemulti
    • icepack
    • icepll
    • iceprog
    • icetime
    • chip databases

If you want to compile and install all four yourself and install in the default /usr/local location, then you can use Dimitri del Marmol's excellent icetools set of scripts. Just run icestorm.sh and you're set.

If you also want to visualize simulated waveforms you have to install a fifth tool GTKWave.

Linux

You can also install the tools

apt-get install verilog  
apt-get install icestorm  
apt-get install fpga-icestorm  

Optional:

apt-get install gtkwave  

Mac OS X

If you use Mac homebrew it is not a good idea to install into /usr/local. You can use the following steps to install all four:

Prerequisites

brew install bison gawk pkg-config git mercurial graphviz python python3 libftdi0 libffi  

Yosys and Icarus-Verilog

Fortunately yosys and iverilog are already packaged in homebrew:

brew install yosys icarus-verilog  

Unfortunately, arachne-pnr and icestorm are not available on homebrew, yet, so we have to build them ourselves.

Icestorm

git clone https://github.com/cliffordwolf/icestorm.git  
cd icestorm  
PYTHONPATH=`brew --prefix`/lib/python$PYTHONVERSION/site-packages/ make -j  

I don't want to install the tools in /usr/local because that's owned by homebrew. Instead I'd like to use $HOME/.local:

# dry run. Remove the -n to actually install
make -n install DESTDIR=$HOME/.local PREFIX=  

Arachne-pnr

Arachne-pnr consists of the executable and three chip databases that contain the details of the topologies. Again, I choose to install into .local instead of the default /usr/local:

git clone https://github.com/cseed/arachne-pnr.git  
cd arachne-pnr  
make -n PREFIX=$HOME/.local  
make -n PREFIX=$HOME/.local install  

libftdi0

The iceprog programmer is responsible for burning the bitstream onto the device. iceprog uses the libgtdi0 library which cannot be used while the official FTDI USB serial driver is installed. To check whether FTDI's driver is installed run

kextstat | grep FTDIUSBSerialDriver  

Then, if necessary, uninstall the FTDI driver.

sudo kextunload -b com.FTDI.driver.FTDIUSBSerialDriver  

The driver can be re-installed with the opposite command:

sudo kextload -b com.FTDI.driver.FTDIUSBSerialDriver  

Optional: GTKWave

brew install caskroom/cask/gtkwave  

Blinky

Blinky is the "Hello World" for FPGAs. The goal is to get the green LED of the iCEStick board to blink continuously.

Verilog

blinky.v

// blinky.v
// Blink the green LED with frequency 12e6/2^24 = 0.7Hz approx.
module top (clk_in, led_green_out, led_red_out);  
    input clk_in;
    output led_green_out;


    reg [23:0] counter;
    assign led_green_out = counter[23];
    assign led_red[3:0] = 4'b0;

    always @ (posedge clk_in) begin
        counter <= counter + 1;
    end

endmodule  

Pin assignment blinky.pcf:

set_io clk_in 21  
set_io led_green_out 95  
set_io led_red[0] 96  
set_io led_red[1] 97  
set_io led_red[2] 98  
set_io led_red[3] 99  
yosys -p "synth_ice40 -top top -blif build/blinky.blif" blinky.v  
arachne-pnr -d 1k -P tq144 -o build/blinky.asc -p blinky.pcf build/blinky.blif  
icepack build/blinky.asc build/blinky.bin  
iceprog build/blinky.bin  

Here's a Makefile for this workflow:

all: build/blinky.bin

build/blinky.bin: build/blinky.asc  
    icepack $< $@

build/blinky.asc: blinky.pcf build/blinky.blif  
    arachne-pnr -d 1k -P tq144 -o $@ -p $^

build/blinky.blif: blinky.v  
    yosys -p "synth_ice40 -top top -blif $@" $^

prog: build/blinky.bin  
    iceprog build/blinky.bin

clean:  
    rm build/*

.PHONY: prog clean

The default target is build/blinky.bin. To write this to flash invoke the prog target. Finally, clean the build directory with the clean target.

Simulation

Time->Zoom->Zoom Full

GTKWave User's Guide

Resources

Other Build scripts

PlatformIO

"PlatformIO is an open source ecosystem for IoT development"

Platform.io support a few iCE40 boards.

Verilog