iCE40 and the IceStorm Open Source FPGA Workflow

Introduction

Project IceStorm is the first, and currently only, fully open source workflow for FPGA programming. The toolchain targets the iCE40 series of FPGAs from Lattice Semiconductor. It enables you to take a project from high-level Verilog code to a synthesized bitstream and then use that bitstream to program an FPGA, generally by loading the bitstream to flash memory on a development board or other circuit housing one of the supported chips.

An FPGA (field programmable gate array) is an integrated circuit made up of user programmable logic blocks, accompanied by an assortment of interconnects, memory, and input/output functionality. Using an HDL (hardware description language) like Verilog, the FPGA can be configured as a digital logic circuit. The complexity of that circuit is essentially only limited by the resources (logic blocks and memory) on the chip. Modern FPGAs have many thousands of logic blocks and can be used to implement complete large-scale computing circuits.

These days, it is easy to become complacent about the availability of quality open source tools for just about any tech task. But the existence of IceStorm is really quite the noteworthy accomplishment for developers Clifford Wolf and Mathias Lasser. FPGA manufacturers have been notoriously protective of their intellectual property. Creating a functioning workflow required a deep reverse engineering of the iCE40 FPGA structure and the format of the configuration data (the bitstream) used in programming. No mean feat with scant documentation available and no support from the manufacturer.

I've been aware of Project IceStorm since it was first announced in 2015. But my interest was heightened recently when I began experimenting with Yosys, Wolf's open source Verilog synthesis and verification tool. Yosys provides synthesis for the IceStorm toolchain, but is also extremely useful in its own right.

I started using Yosys in my own Verilog work because of the granularity it provides. The Yosys process is script-based and very transparent. You can set up a synthesis project and check in at multiple points in the flow to see what the software is doing. If you are interested in the actual synthesis process - turning a high-level description of digital logic into a functional, optimized circuit - the transparency of Yosys makes it a particularly informative tool. And of course, as a FOSS project it is free to download and use.

In addition to Yosys, the primary tools of the IceStorm flow include Arachne-PNR, which maps the synthesized logic to the specific FPGA hardware being programmed, IcePack/IceUnpack, which converts the bitstream into the ASCII format used by IceStorm, and IceProg, an FTDI driver used in programming development boards. See Wolf's Github for the most up-to-date version of IceStorm and the Project IceStorm page at Wolf's website for project status, notes on installation, etc.

Of course to put IceStorm to work, you'll need some type of iCE40 target board. Lattice makes several inexpensive boards, notably (at the time of this writing) the Lattice iCEstick and the Lattice iCE40-HX8K Breakout Board. For my own experiments, I'm using an Olimex iCE40HX8K-EVB. This nice open hardware board has the iCE40 version with 7680 logic cells, currently the largest of the series, along with 2MB of serial flash. The board also has a lot of available I/O which is important to me.

The board is setup to be programmed via SPI. You can use a microcontroller such as an Arduino for programming, provided it will operate at 3.3V. You can also use a Raspberry Pi. Amazingly, Project IceStorm is lightweight enough that it will run comfortably on a Raspberry Pi, meaning that the Pi can not only be used as a programmer, but for the synthesis workflow too.

To get started, I picked up an Olimexino-32U4, Olimex's Arduino Leonardo variant, to use as a programmer. The Olimexino-32U4 has a 3.3V jumper setting and an Olimex UEXT port so that you can connect the Olimexino-32U4 and the iCE40HX8K-EVB with a simple 10-pin IDC cable. Olimex has a sketch for the Arduino as well as a utility (iceprogduino) to be added to the IceStorm workflow to support the process, making this seem like a reasonably no-fail approach.

The software installation went off without a hitch. Following the instructions at Project IceStorm, I built the various packages from source on my desktop box running Ubuntu Linux 16.04. Following the instructions from Olimex I was able to install the firmware sketch on the Olimexino and build iceprogduino on the desktop.

Olimex has a handy little "Hello World" project that flashes the built-in LEDs under control of the built-in pushbuttons. Using that project as a base, I implemented a binary counter project as my own test that the toolchain and hardware were working. The binary counter (or binary clock) displays a binary number on a row of LEDs, starting at zero and then incrementing by one each cycle until it rolls back over to zero and begins again.

IceStorm requires the preparation of two text files. The first is a *.v standard Verilog file. The second is a *.pcf pin assignment file that correlates the inputs and outputs declared in the Verilog code to the physical I/O pins on the FPGA. Additionally, a makefile is very helpful for automating the many steps of synthesis and configuration. The two necessary files and the makefile from my project are repeated below:

counter.v

/* module */
module top (

    input CLK,
    output LED1,
    output LED2,
    output LED3,
    output LED4,
    output LED5,
    output LED6,
    output LED7,
    output LED8,
    
);

    /* reg */
    reg [32:0] counter;
    
    /* assign */
    assign LED1 = counter[24];
    assign LED2 = counter[25];
    assign LED3 = counter[26];
    assign LED4 = counter[27];
    assign LED5 = counter[28];
    assign LED6 = counter[29];
    assign LED7 = counter[30];
    assign LED8 = counter[31];

    
    /* always */
    always @ (posedge CLK) begin
        counter <= counter + 1;
    end

endmodule

counter.pcf

set_io CLK J3
set_io LED1 G3
set_io LED2 F3
set_io LED3 E2
set_io LED4 H3
set_io LED5 H5
set_io LED6 F2
set_io LED7 E3
set_io LED8 H6

makefile

PROJ = counter
PIN_DEF = counter.pcf
DEVICE = hx8k

all: $(PROJ).rpt $(PROJ).bin

%.blif: %.v
	yosys -p 'synth_ice40 -top top -blif $@' $<

%.asc: $(PIN_DEF) %.blif
	arachne-pnr -d $(subst hx,,$(subst lp,,$(DEVICE))) -o $@ -p $^ -P ct256

%.bin: %.asc
	icepack $< $@

%.rpt: %.asc
	icetime -d $(DEVICE) -mtr $@ $<

prog: $(PROJ).bin
	sudo iceprogduino $<

sudo-prog: $(PROJ).bin
	@echo 'Executing prog as root!!!'
	sudo iceprogduino $<

clean:
	rm -f $(PROJ).blif $(PROJ).asc $(PROJ).bin $(PROJ).rpt

.PHONY: all prog clean

Again, my files above intentionally track very closely to the Olimex project. My Verilog winds up being considerably simpler.

An important distinction between the Olimex "Hello World" and my binary counter is the need to interface to external LEDs. There are only two LEDs on the board, and the binary counter requires eight. The code in counter.pcf should be fairly self-explainatory. LED1, which was identified as an output in counter.v, is assigned to pin G3 in counter.pcf, LED2 is assigned to pin F3, and so on. My source for the pin numbers is the schematic provided by Olimex. Extracted from the schematic, the graphic below shows the correlation between pins on the board's GPIO header and the actual FPGA pins.

Note that the makefile specifies this project in the PROJ and PIN_DEF lines. To use this makefile in another project you would specify your own project files appropriately. Also note that the makefile specifies the iCE40 part (hx8k), and that IceStorm is to use iceprogduino for the programming interface.

With these three files in place, the project can be built and implemented with two entries at the command line:

make

make_prog

As with the installation, the demo project synthesized and programmed without any issues. So far I'm very satisfied with the functionality and ease-of-use with the IceStorm workflow. Although my own test project was too small to be a full proof, there is plenty of evidence that the workflow scales up without much problem. Wolf himself demonstrated the implementation of a small but complete RISC-V processor called PicoRV32.

Next up I'll give IceStorm a workout of my own, setting up a series of successively more complex logic circuits using IceStorm and the iCE40HX8K-EVB board.

January 24, 2018


About the Author: Ralph Heymsfeld is the founder and principal of Sully Station Solutions. His interests include artificial intelligence, machine learning, robotics and embedded systems. His writings on these on other diverse topics appear regularly here and across the Internet.


Other Posts

An Arduino Neural Network
An artificial neural network developed on an Arduino Uno. Includes tutorial and source code.

Buster - A Voice Controlled Raspberry Pi Robot Arm
Buster is a fully voice interactive robot arm built around the Raspberry Pi. He acts upon commands given in spoken English and answers questions too.

Migrating to the 1284P
The ATMEGA1284P is one of the more capable microcontrollers available in the hobbyist and breadboard-friendly 40-pin PDIP package. Here I discuss migrating the neural network project to the 1284p to take advantage of its relatively generous 16K RAM.

Getting Up and Running With a Tamiya Twin-Motor Gearbox
Tamiya makes a full line of small gearbox kits for different applications that are capable for their size and an easy, economical way to get a small to medium size wheeled robot project up and running.

Flexinol and other Nitinol Muscle Wires
With its unique ability to contract on demand, Muscle Wire (or more generically, shape memory actuator wire) presents many intriguing possibilities for robotics. Nitinol actuator wires are able to contract with significant force, and can be useful in many applications where a servo motor or solenoid might be considered.

Precision Flexinol Position Control Using Arduino
An approach to precision control of Flexinol contraction based on controlling the voltage in the circuit. In addition, taking advantage of the fact that the resistance of Flexinol drops predictably as it contracts, the mechanism described here uses the wire itself as a sensor in a feedback control loop.

LaunchPad MSP430 Assembly Language Tutorial
One of my more widely read tutorials. Uses the Texas Instruments LaunchPad with its included MSP430G2231 processor to introduce MSP430 assembly language programming.

K'nexabeast - A Theo Jansen Style Octopod Robot
K'nexabeast is an octopod robot built with K'nex. The electronics are built around a PICAXE microcontroller and it uses a leg structure inspired by Theo Jansen's innovative Strandbeests.



Home