Getting Started with FPGAs
https://github.com/minsun-ss/learning-fpgas
As part of W1'25 Recurse batch, my resolution for this batch was to do something interesting with FPGAs and maybe eventually commit something more substantial to Tiny Tapeout in March 2026. It made sense to start working with nandland’s Getting Started with FPGAs book, and while I was happy to do this exploration exercise with the nandland go board, I was pretty reluctant to work with the iceCube2 tooling since it seemed unwieldy (buggy on Linux and didn’t really want to work in Windows for this batch). Fortunately for all of us, there is a lot of open source tooling around iCE40 boards that is (relatively) easy to set up once you understand all the moving parts.
Some note: I did this all on Debian 13 (Trixie). I eventually plan to replicate the workflow on my Mac laptop (M2), but think most of this workflow is agnostic (mostly) to OS; in Windows, I do think maybe setting up the iceCube2 workflow is honestly the easiest way to go if you do not intend to use WSL 2.
iCE40 FPGA Boards
I am assuming here that you are using an iCE40 board of some sort for working through the project. For a complete beginner (I put myself squarely in this camp), the nandland go board is quite nice to start with the projects as you don’t need to stare at schematics to figure out pins (it’s provided for you in the book) and it’s just one less thing to worry about at the beginning, especially since we are removing the scaffolding of using the iceCube2 design software. If you do go with iceCube2, though, the license requires emailing Lattice and waiting; this took about a week for me.
If you use the nandland go board, you can find schematics on nandland; a copy of this pdf is also contained in the repo under /docs.
Installing the tooling
The suggested tools to install, in no particular order, are:
Synthesis, Place and Route, Programming:
- Yosys Open SYnthesis Suite (YoSys)
- IceStorm Tools (Project IceStorm)
- NextPNR
Simulation, Test benches, Waveforms:
- Icarus Verilog (iverilog)
- GTKWave
There is a lot of overlap between the instructions for all of the above, some of which are detailed below. If you start with reading Project Icestorm docs first, you’ll see that Project IceStorm suggests you install a lot of things already: IceStorm tools, arachne-pnr, next-pnr, yosys. Of the four, you only need three; ignore arachne-pnr, as it’s been fully superceded by nextpnr.
With that said, a lot of stuff online still uses arachne-pnr in their makefiles and you might need to fiddle with it, so it’s good to know that it was commonly used. For the case of iCE40 boards, though, there’s virtually no difference between nextpnr and arachne except for nextpnr’s use of json format rather than blif; that requires subbing out the -blif output flag in yosys to -json and that’s pretty much it; everything else can remain the same.
The last thing to note is that some of these tools do not necessarily need to be installed separately: if you decide to use yosys via the suggested oss-cad-suite set of binaries then you do not, in fact, need to build anything at all; all of the above tools are part of the oss-cad-suite already in the /bin:
reginleif:/opt/oss-cad-suite $ cat VERSION
20251113
@reginleif:/opt/oss-cad-suite/bin $ ls
aigand cvc4 icebox_maps smvtoaig
aigbmc cvc5 icebox_stat soltostim
aigcexmin dfu-prefix icebox_vlog suprove
aigdd dfu-suffix icebram surfer
aigdep dfu-util icefunprog surver
aigflip dot icemulti tabbyadm
aigfuzz ecpbram icepack tabbypip
aiginfo ecpdap icepll tabbypy3
aigjoin ecpmulti iceprog tinyfpgab
aigmiter ecppack iceprogduino tinyprog
aigmove ecppll icesprog twinwave
aignm ecpprog icetime vcd2fst
aigor ecpunpack iceunpack vcd2lxt
aigreset eqy imctk-eqy-engine vcd2lxt2
aigselect evcd2vcd iverilog vcd2vzt
aigsim find_libpython iverilog-vpi verilator
aigsplit fst2vcd lsftdi verilator_bin
aigstrip fstminer lsusb verilator_bin_dbg
aigtoaig fujprog lxt2miner verilator_coverage
aigtoblif ghdl lxt2vcd verilator_coverage_bin_dbg
aigtobtor ghdl1-llvm mcy verilator_gantt
aigtocnf ghwdump mcy-dash verilator_profcfunc
aigtodot gmpack mcy-gui vvp
aigtosmv gmunpack nextpnr-ecp5 vzt2vcd
aiguncomment gowin_pack nextpnr-generic vztminer
aigunconstraint gowin_pll nextpnr-himbaechel wrapstim
aigunor gowin_unpack nextpnr-ice40 xdot
aigunroll gtkwave nextpnr-machxo2 xml2stems
amaranth-rpc hex2bin nextpnr-nexus yices
andtoaig hex2dump openFPGALoader yices-sat
avy hexdiff openocd yices-smt
avybmc hexinfo pono yices-smt2
bin2hex hexmerge prjoxide yosys
bitwuzla icebox_asc2hlc pyserial-miniterm yosys-abc
black-iceprog icebox_chipdb pyserial-ports yosys-config
bliftoaig icebox_colbuf rtlbrowse yosys-filterlib
boolector icebox_diff sby yosys-smtbmc
btormc icebox_explain sby-gui yosys-witness
btorsim icebox_hlc2asc scy z3
cocotb-config icebox_html shmidcat
There is a shell script in the oss-cad-suite that you can activate that will give you access to those tools. Pretty easy, eh? Wish I had figured this out after building and installing all of the above. But my loss is your time savings! From here I’ll presume that you’ll be using oss-cad-suite, although in the repo I do have some notes on the builds for the above tools if you decide to build them separately. I wrote a very simple script to stuff into my .bashrc to activate the env and dumped the oss cad suite into my /opt. Maybe there’s a better way to source virtual env shells, but I’ve never found a great way for doing it in a simple way.
fpgashell() {
source /opt/oss-cad-suite/environment
}
With that you’re almost ready to go, although there’s one other thing you should set up, although it’s optional since it’s dependent on the board.
In Project Icestorm’s docs, they suggest creating a 53-lattice-ftdi.rules file to put in your /etc/udev/rules.d; this allows you to simply call iceprog to flash your fpga without requiring sudo. A copy of this .rules is in the /tools folder in the repo. You can verify that the vendor id and product id in the rules file matches your nandland device by calling lsusb (there’s probably better ways of doing this but I found this the easiest):
@reginleif:/opt/oss-cad-suite/bin $ lsusb
Bus 007 Device 016: ID 0403:6010 Future Technology Devices International, Ltd FT2232C/D/H Dual UART/FIFO IC
Bus 005 Device 097: ID 20b7:9db1 Qi Hardware Glasgow Debug Tool
0403 is the vendor id and 6010 is the product id of the nandland go board. I’ve included the similar info list for the Glasgow Interface Explorer, which is another board that also uses a iCE40 FPGA for comparison.
Running the workflow
For the book, the workflow is similar to how it’s presented in the book: verilog/pcf/sbc/module names are the same per project. The makefile included in the repo will build any project stored inside /src and output the results in the /build folder:
make build PROJ=projectname
/src should contain each program in its own self contained folder; see the repo for structure. This was mostly just to ease having multiple projects to work through in a single repo. To program your FPGA once you finish building, you can call the ship command and it’ll program the fpga with your specified *.bin file as long as the FPGA is plugged in.
make ship PROJ=projectname
If you do not use the nandland go board, then you will need to figure out what iCE40 device and package you need to use for synthesis. You’ll have to refer to the datasheets for your device and then cross reference it against Lattice datasheets. A copy of Lattice’s datasheet is included in the repo for you to check against.
Once you know both, replace the value in the DEVICE and PACKAGE parameters for your board in the top of the Makefile.
For the nandland go board the device is hx1k and the package is vq100 (these are set already as defaults in the makefile); you can actually verify this using the go board constraint pcf provided by nandland:
# iCEcube PCF
# Version: 2014.12.27052
# File Generated: Apr 27 2015 09:46:33
# Family & Device: iCE40HX1K
# Package: VQ100
I’ve also included a copy of this .pcf file under the /src folder for convenience.
Differences Between Book & Using Open Source tooling
The repo, under /docs, contains a document that goes through, chapter by chapter, the major differences between using the iceCube2 suite of tools vs open source tooling. Where possible; I’ve provided roughly equivalent substitute commands to achieve parity and describe to some detail some of the differences, including what you need to modify in the book code to make work for OSS tooling. For the most part, it seems to be very little; e.g., for simulation I would suggest adding the timescale direction at the top of your files to make GTKwave produce the correct resolution waveforms for you out of the box, but that’s about it so far.
Additional Reading
A list of additional materials I read that I found interesting.
- CMOS VLSI Design: A Circuits And Systems Perspective, 4th Edition
- Getting Started With FPGAs - the book I worked from
- Alibaba cloud FPGA: the 200$ Kintex UltraScale+ - the post that gave me the push to get started, but also the person who gave me an amazing make build setup for iCE40 that I learned a lot from - I modified it very heavily but it gave me all the pointers in the right direction.
To be continued!
I intend to cover some of the things I’ve learned in additional posts:
- formal verification is on my to do list!
- covering some of the other tools in the oss-cad-suite. Almost every step of the fpga process, e.g., synthesis, placement/routing, timing, etc, seems to have at least 2 tools to compare against in the suite; it is worth investigating.