The iCEBreaker board is the first FPGA development board with a fully open-source toolchain, which allows to go all the way from HDL code to configuration bitstream. All the schematics and hardware information is openly available at no extra cost.
The iCEBreaker board features a Lattice iCE40UP5K FPGA with the following integrated components:
- 5280 PLB’s consisting of one 4-input LUT, carry-chain and one FF each
- 128 Mbit dual-port BRAM’s
- 1 MBit single-port BRAM’s
- 8 DSP’s
- 1 programmable PLL and 2 on-chip oscillators
- 2 hard-IP’s for SPI and I2C each
- 3 hard-IP’s for PWM
- Up to 32 user IO pins. The IO pins are available as 3 PMOD edge connectors
- One PMOD module with 3 push-buttons and 5 LEDs is included
- On-board FTDI FT2232H for easy FPGA configuration and debugging via USB
- 128 Mbit Winbond QSPI flash, programmable over USB or via a separate SPI pin-header
The remainder of this article will guide through the procedure of setting up the open-source toolchain for the iCEBreaker. No Lattice tools and software will be used, maybe that will be covered another time. In a final step the toolchain will be tested by implementing and loading a simple example design. The OS will be asusmed to be Ubuntu 18.04 for the rest of this article.
Let’s begin by installing the dependencies which are required to build the toolchain. The command below will install the superset of all dependencies which are required for the steps that follow.
$> sudo apt install build-essential clang bison flex libreadline-dev gawk tcl-dev libffi-dev git mercurial graphviz xdot pkg-config python python3 libboost-system-dev libboost-python-dev libboost-filesystem-dev libftdi-dev qt5-default python3-dev libboost-all-dev cmake libeigen3-dev
Next clone the github repository for yosys, the synthesis tool of the toolchain. The latest stable release/tag of yosys is recommended, but instead the latest master branch can also be used.
$> git clone https://github.com/yosyshq/yosys $> cd yosys $> git checkout yosys-v0.9 $> make -j(nproc) $> sudo make install
Continue with the bitstream generation tool icestorm.
git clone https://github.com/cliffordwolf/icestorm cd icestorm make -j$(nproc) sudo make install
Finally we have to choose between the place-and-route tool nextpnr and arachne-pnr. Since arachne-pnr is considered obsolete it’s successor nextpnr should be used. Since I like to play around and compare results between different tools I will install both, but note that only one of the two is required.
$> git clone https://github.com/yosyshq/nextpnr $> cd nextpnr $> cmake -DARCH=ice40 $> make -j$(nproc) $> sudo make install
$> git clone https://github.com/yosyshq/arachne-pnr $> cd arachne-pnr $> make -j$(nproc) $> sudo make install
That concludes the setup of the toolchain. Time for an example, to see if everything works.
Now that we are all set, let’s try to synthesize a simple example design, run the place-and-route tool and generate a bitstream for the iCEBreaker.
$> yosys -p "synth_ice40 -top icebreaker_top -blif icebreaker_top.blif" src/icebreaker_top.v $> arachne-pnr -d 5k icebreaker_top.blif -o icebreaker_top.asc $> icepack icebreaker_top.asc icebreaker_top.bin $> iceprog icebreaker_top.bin
Aaaand the board is bricked (for the moment)! The iCEBreaker no longer is properly recognized neither by Ubuntu nor my Windows 10 machine. It took me a few moments to understand what had gone wrong, but not close to as long as I feared it would take.
Well, the problem was that no physical constraint file (.pcf) was passed to arachne-pnr. The .pcf file defines which top module port is connected to which physical package pin. Without this information arachne-pnr will choose these pins assignments arbitrarily, like most place-and-route tools do in such a situation. After asking arachne-pnr to output the pin assignments it had chosen (-w option) the problem became very clear.
$> arachne-pnr -d 5k icebreaker_top.blif -o icebreaker_top.asc -w icebreaker_top.asc.pcf ... (some irrelevant output) $> cat icebreaker_top.asc.pcf $> arachne-pnr 0.1+328+0 (git sha1 c40fb22, g++ 7.4.0-1ubuntu1~18.04.1 -O2) set_io led_o 35
Cross-checking this with the iCEBreaker pinout-sheet or schematic and we can see that pin 35 is actually connected to the external 12 MHz oscillator output. Unfortunately this oscillator also drives the FTDI chip (FT2232) which takes care of the USB connection to the outside world. Driving a dumb blinky LED signal on that pin will wreak havoc on the 12 MHz clock signal and mess with the FTDI chip.
To fix this issue the CRESET jumper on the board must be closed. Setting the CRESET jumper will keep the FPGA in reset. This way no output pin of the FPGA is driven and we have time to replace the bitstream in the SPI flash with one that doesn’t do any harm.
So let’s try again, this time with the correct .pcf file.
$> arachne-pnr -d 5k icebreaker_top.blif -o icebreaker_top.asc -p constr/icebreaker_top.pcf -w icebreaker_top.asc.pcf ... (some irrelevant output) $> icepack icebreaker_top.asc icebreaker_top.bin $> iceprog icebreaker_top.bin
The example from this article – and hopefully some more advanced stuff in the near future too – will be available on my iCEBreaker github repository.
That’s it for today. See you next time.