From Netlist to Silicon: Place and Route with NextPNR on WSL
From Netlist to Silicon: Place and Route with NextPNR on WSL
Welcome back to the final installment of our AppliedKaos beginner series on low-latency FPGA design!
In Part 1, we wrote and simulated a SystemVerilog glitch filter. In Part 2, we used Yosys to synthesize that code into a generic hardware netlist—proving our logic was physically buildable.
Today, we cross the finish line. We are going to take that generic netlist, map it to a specific physical FPGA chip, and generate the final binary file (the bitstream) that makes the hardware tick. To do this, we’ll use NextPNR and the Project IceStorm tools, remaining entirely within our open-source WSL Ubuntu 22.04 ecosystem.
The Final Hurdles: PnR and Bitstreams
Before we dive into the commands, let's clarify what is actually happening in this final stage.
What is Place and Route (PnR)?
Yosys gave us a netlist of logic gates and flip-flops, but it didn't tell us where those components should physically sit on the FPGA die. FPGAs are grids of thousands of identical Logic Cells (LCs) and routing switches.
Place and Route is the highly complex process of:
Placement: Assigning each gate from your netlist to a specific physical Logic Cell on the chip.
Routing: Activating the microscopic silicon switches to connect the wires between those specific cells, ensuring the electrical signals arrive on time (meeting timing constraints).
What is a Bitstream?
FPGAs are SRAM-based, meaning they forget their configuration when powered off. A bitstream is the literal .bin file containing the millions of 1s and 0s that tell the FPGA exactly how to configure its internal switches on boot-up.
Our Target: The Lattice iCE40
For this tutorial, we will target the Lattice iCE40 family—specifically, the popular and affordable iCEstick development board (which houses an iCE40-HX1K). The iCE40 was the first FPGA to be fully reverse-engineered, giving birth to the robust open-source toolchain we are using today.
Step-by-Step Instructions
Ensure your OSS CAD Suite is still active in your WSL terminal. If you open a new terminal, remember to run export PATH="$HOME/tools/oss-cad-suite/bin:$PATH".
Step 1: Create a Physical Constraints File (PCF)
Your SystemVerilog module has generic inputs and outputs (clk, rst_n, glitchy_in, clean_out). The FPGA doesn't know which physical metal pins on the outside of the chip correspond to these names. We define this mapping in a PCF (Physical Constraints File).
Create a new file in your ~/kaos_fpga_filter directory named glitch_filter.pcf:
# glitch_filter.pcf - Pin mapping for Lattice iCEstick (HX1K TQ144 package)
# The onboard 12MHz clock
set_io clk 21
# Mapping our inputs to the expansion header pins
set_io rst_n 78
set_io glitchy_in 112
# Mapping our output to one of the onboard green LEDs
set_io clean_out 95
Step 2: Place and Route with NextPNR
Now we feed our Yosys-generated JSON netlist and our PCF constraints file into NextPNR.
Run the following command in your terminal:
nextpnr-ice40 --hx1k --package tq144 --json glitch_filter_netlist.json --pcf glitch_filter.pcf --asc glitch_filter.asc
Let's break this down:
nextpnr-ice40: The specific NextPNR executable for the iCE40 architecture.--hx1k --package tq144: Tells the router exactly which silicon die and plastic package we are using.--json: The input netlist from Yosys.--pcf: Our pin mapping file.--asc: The output file format (an ASCII text representation of the routed chip).
Note: You will see an output log detailing the device utilization. Since our glitch filter is tiny, it will likely use less than 1% of the available logic cells! NextPNR will also report the maximum estimated clock frequency.
Step 3: Generate the Bitstream with Icepack
The .asc file is human-readable, but the FPGA needs binary. We use a tool from Project IceStorm called Icepack to compress and pack the ASCII file into the final bitstream.
Run this command:
icepack glitch_filter.asc glitch_filter.bin
Congratulations! You now have a glitch_filter.bin file. This is the custom hardware personality you just created.
Step 4: Flashing the FPGA (The WSL Caveat)
The final step is to flash the .bin file to the FPGA using a tool called Iceprog:
iceprog glitch_filter.bin
Important WSL Note: By default, WSL 2 does not have access to your Windows USB ports. To use iceprog from inside WSL, you have two choices:
The Native Way: Copy the
glitch_filter.binfile to your Windows desktop and run the Windows version oficeprog(or a GUI tool like Icestudio) directly from Windows.The USB/IP Way: Install
usbipd-winon Windows, which allows you to physically pass the USB connection of your FPGA board through the hypervisor and into your Ubuntu 22.04 environment.
Conclusion
You’ve done it! You have traversed the complete open-source FPGA pipeline: from simulating deterministic, low-latency logic in SystemVerilog, to synthesizing gates with Yosys, and finally routing physical silicon paths with NextPNR.
By mastering this workflow, you aren't just writing software; you are sculpting bespoke hardware architectures tailored perfectly to your high-speed, low-latency needs.
Stay Kaotic,
The AppliedKaos Team
Comments
Post a Comment