A (mostly) free FPGA Development workflow for macOS

For better or worse I'm a macOS user. I enjoy its Unix likeness and thoughtful user experience. However, one area it lacks is FPGA development. Major vendors simply have no support for it, forcing users to rely on virtual machine environments or migrate to a different supported platform.

However, with growing community support for open-source toolchains, particularly around the iCE40 platform, it's easier than ever to synthesize and deploy designs directly on macOS.

💡
I've been testing this workflow using the Alhambra II and Alchrity Cu which are both based on the iCE40HX so your mileage may vary.

Toolchain

Tools that I use in my workflow are a part of the oss-cad-suite distribution which contains a number of open source software used in digital logic design. The specific tools I use from the suite include:

These are managed inside of a simple Makefile that has the various steps in the workflow outlined.

BUILD_DIR=build
SOURCE_DIR=source
CONSTRAINT_DIR=constraint
TOP_MODULE=Top

YOSYS ?= yosys
YOSYS_FLAGS ?= -q
NEXT_PNR ?= nextpnr-ice40
NEXT_PNR_FLAGS ?= --hx8k --package cb132

.PHONY: clean
clean:
	rm -rf $(BUILD_DIR)/ && mkdir $(BUILD_DIR)/

.PHONY: schematics
schematics: 
	./scripts/schematics

.PHONY: benches
benches: 
	./scripts/benches

.PHONY: sys
sys: $(BUILD_DIR)/out.json

.PHONY: constraints
constraints: all.pcf

.PHONY: pnr
pnr: $(BUILD_DIR)/out.asc

.PHONY: program
program: $(BUILD_DIR)/out.bin
	iceprog $(BUILD_DIR)/out.bin

$(BUILD_DIR)/out.bin: $(BUILD_DIR)/out.asc
	icepack $(BUILD_DIR)/out.asc $(BUILD_DIR)/out.bin

$(BUILD_DIR)/out.asc: $(BUILD_DIR)/out.json all.pcf
	$(NEXT_PNR) $(NEXT_PNR_FLAGS) --json $(BUILD_DIR)/out.json  --pcf $(BUILD_DIR)/all.pcf  --asc $(BUILD_DIR)/out.asc

$(BUILD_DIR)/out.json: $(SOURCE_DIR)/*.sv
	$(YOSYS) $(YOSYS_FLAGS) -p 'synth_ice40 -top $(TOP_MODULE) -json $(BUILD_DIR)/out.json' $(SOURCE_DIR)/*.sv

all.pcf:
	cat $(CONSTRAINT_DIR)/*.pcf > $(BUILD_DIR)/all.pcf
Sample Makefile

To manage the version of the OSS CAD Suite I have installed, I made a tool that allows me to specify the distribution version with the project. It ships as a single binary with no dependencies.

GitHub - nishtahir/icicle: An OSS CAD Suite Version Manager
An OSS CAD Suite Version Manager. Contribute to nishtahir/icicle development by creating an account on GitHub.

You can install these tools directly, using icicle or via another package manager such as apio

Editor Support

Great editor support is important and I wanted my workflow to be compatible with VSCode. I tried various extensions but ended up settling on mshr-h/vscode-verilog-hdl-support.

GitHub - mshr-h/vscode-verilog-hdl-support: Verilog HDL/SystemVerilog/Bluespec SystemVerilog support for VS Code
Verilog HDL/SystemVerilog/Bluespec SystemVerilog support for VS Code - GitHub - mshr-h/vscode-verilog-hdl-support: Verilog HDL/SystemVerilog/Bluespec SystemVerilog support for VS Code

It comes with basic syntax highlighting and linting for Verilog and SystemVerilog. It's easy to configure the extension to use iverilog as its linting engine required some settings to work with my project structure. This is easily added as a workspace configuration setting in VSCode.

{
    "verilog.linting.iverilog.arguments": "-g 2012 -Y .sv -y source/ ",
    "verilog.linting.linter": "iverilog",
    "verilog.logging.enabled": true
}
.vscode/settings.json

While it lacks advanced IDE features like goto definitions and project outlining it has been good enough for my use case. As a result, more sophisticated extensions such as TerosHDL may be better for your workflow.

Simulation

I run simulations with Icarus Verilog. However, you can use other tools like Verilator if you wanted to. I have my test benches create a Waveform dump.

module TestModule;
  ...
  
  initial begin
    $dumpfile("build/TestModule.vcd");
    $dumpvars(0, TestModule);
    ...
  end
endmodule

Executing the simulation is pretty straight forward using iverilog and the vvp commands.

iverilog -g2012 -Y .sv -y source/ -o $BUILD_DIR/$MODULE.iverilog $BENCH_FILE
vvp $BUILD_DIR/$MODULE.iverilog 

Inspecting the *.vcd file is possible with GTKWave which is included in the OSS CAD Suite.

$ gtkwave build/TestModule.vcd

While this worked flawlessly, I wanted something more integrated with VSCode so I could view signals beside my test benches. I discovered WaveTrace which fills this use-case incredibly well.

WaveTrace - Visual Studio Marketplace
Extension for Visual Studio Code - Interactive VCD waveform viewer for FPGA/RTL developers

While it isn't FOSS, it does have a free tier for supporting up to 8 signals.

Schematics Generation

The best tool I've come across for schematic generation so far is netlistsvg. It is a JavaScript project so you will need Node.JS installed.

GitHub - nturley/netlistsvg: draws an SVG schematic from a JSON netlist
draws an SVG schematic from a JSON netlist. Contribute to nturley/netlistsvg development by creating an account on GitHub.

It works by using synthesized YoSYS netlists as an input in order to generate some well-laid-out *.svg schematics. It's not super sophisticated about groupings and can have trouble with parameterized modules in my experience (I'm chalking this up to user error), but it does a great job of giving a high-level view of my designs.

Schematic Editing

Following the retirement of Logisim, a couple of projects have emerged to take its place. These include Logisim Evolution and Digital.

GitHub - hneemann/Digital: A digital logic designer and circuit simulator.
A digital logic designer and circuit simulator. Contribute to hneemann/Digital development by creating an account on GitHub.

Of those, I've currently spent the most time with Digital. It requires no installation and ships as a runnable cross-platform *.jar file (This means that you will need Java installed). It has a fairly decent component library which allows you to describe custom components in HDL.

It includes a fairly capable built-in simulator. And can export designs to VHDL and Verilog.

/*
 * Generated by Digital. Don't modify this file!
 * Any changes will be lost if this file is regenerated.
 */

module Sample (
  input A,
  input B,
  output Q,
  output Q_inv
);
  wire Q_temp;
  wire Q_inv_temp;
  assign Q_temp = ~ (A | Q_inv_temp);
  assign Q_inv_temp = ~ (Q_temp | B);
  assign Q = Q_temp;
  assign Q_inv = Q_inv_temp;
endmodule

While I do wish it didn't have the dependency on Java or shipped as a single binary for my platform, I'm just happy that it works as well as it does.

Conclusion

I put this together in hopes that it'll help other macOS users interested in digital design get a head start and while support for major platforms is still lacking, digital design on macOS is clearly viable if you are willing to adopt FOSS tooling. As the toolchains continue to evolve and expand to new platforms with initiatives like F4PGA attempting to target popular platforms like the Xilinx 7 Series, It's hard not to be optimistic about the future.

Subscribe to Another Dev's Two Cents

Don’t miss out on the latest issues. Sign up now to get access to the library of members-only issues.
jamie@example.com
Subscribe