Programming an FPGA with a FOSS toolchain

This is a quick guide on how to program a Sipeed Tang Nano 9K (GOWIN GW1NR-9) using a fully open source toolchain for FPGA programming. I will use Arch Linux but you may find some of the required packages available in your distro’s package repository as well.

Install Yosys and OpenFPGALoader from the official Arch repository with pacman:

sudo pacman -S yosys openfpgaloader

Now you will need to install nextpnr and Project Apicula from AUR. I had a few problems with these packages so I will explain what I’ve done to make it work for me, but try a normal installation first as these problems will likely get fixed in the near future.

First download and install my apicula-git package from AUR.

Then download the nextpnr-git package, also from AUR, and edit the PKGBUILD file to only build your target:

_ARCHS=('himbaechel')

And comment out this dependency:

    himbaechel)
      #makedepends+=('prjapicula')

Now you should be able to makepkg -i, this will take some time so you can brew a mate meanwhile. If everything has gone well you should be able to run nextpnr-himbaechel --version successfully.

At this point you have everything needed to synthesise, route&place, generate bitstreams and upload them into your Tang Nano. Let’s try out the LED example from the Sipeed wiki.

In a new directory create a led.v Verilog file with the following code:

module led (
    input clk,              // clk input
    input rst,              // reset input
    output reg [5:0] led    // 6 LEDS pin
);

reg [23:0] counter;

always @(posedge clk or negedge rst) begin
    if (!rst)
        counter <= 24'd0;
    else if (counter < 24'd1349_9999)       // 0.5s delay
        counter <= counter + 1'b1;
    else
        counter <= 24'd0;
end

always @(posedge clk or negedge rst) begin
    if (!rst)
        led <= 6'b111110;
    else if (counter == 24'd1349_9999)       // 0.5s delay
        led[5:0] <= {led[4:0],led[5]};
    else
        led <= led;
end

endmodule

You will need a CST file for this board; you can find an example in the Apicula’s repo but you can also use this fragment (name it tangnano9k.cst):

IO_LOC "clk" 52;
IO_LOC "led[0]" 10;
IO_LOC "led[1]" 11;
IO_LOC "led[2]" 13;
IO_LOC "led[3]" 14;
IO_LOC "led[4]" 15;
IO_LOC "led[5]" 16;
IO_LOC "key" 3;
IO_LOC "rst" 4;

You are ready to synthesise this design with the following yosys script:

yosys -p "read_verilog led.v; synth_gowin -top led -json led.json"

If the synthesis completes successfully there will be a new led.json file. Next let’s use nextpnr:

nextpnr-himbaechel --json led.json --write pnrled.json --device GW1NR-LV9QN88PC6/I5 --vopt family=GW1N-9C --vopt cst=tangnano9k.cst

After a few seconds you should see a message saying Program finished normally and there should be a new pnrled.json file that we will use to generate the bitstream:

gowin_pack -d GW1N-9C -o led.fs pnrled.json

Now it’s time to grab your dev board :D

Connect the Tang Nano 9K to a USB-C and try this:

openFPGALoader --scan-usb

This should list an FT2232 JTAG Debugger, if it doesn’t then try to unplug and plug again (and avoid sketchy USB hubs ^_^). If you do see the debugger then you can run:

openFPGALoader --detect

This should list a Gowin device and it means we are ready to upload the bitstream:

openFPGALoader -b tangnano9k -f led.fs

Once it’s finished, the six tiny LEDs next to the FPGA should be turning on progressively.