Featured image of post Continuous Integration for Firmware with Github Actions

Continuous Integration for Firmware with Github Actions

Using Github actions to simulate, test and build an FPGA design using Open Source tools

For a couple of months I’ve been slowly building up a little project using some Development boards that include an FPGA, typically once i’ve finished editing my design I run all my simulations, tests and then check I can still build the firmware. While running these manually before each commit isn’t typically much an issue, I wanted to automate this.

The project i’m working on uses a ColorLite i5 FPGA board, this with it Lattice ECP5 FPGA allows me to use a set of Open source tools to test and build my FPGA images. For simulations I’m using Verilator, while for creating the FPGA images I’m using a combination of Yosys and Next-PNR. These excellent tools allow me to make use of the GitHub actions to test my FPGA images with very minimal effort.

While my simulations require a couple of commands so these are contained to a makefile, the commands to build the FPGA image are very simple.

yosys -p 'synth_ecp5 -json top.json' -S firmware/top.v
nextpnr-ecp5 --25k --package CABGA381 --json top.json --lpf firmware/colorlight.lpf --textcfg out.config

To build the FPGA image is a simple task of running my ’top.v’ verilog file though yosys, before doing place and route with nextpnr, which again is a single line. These simple lines allow me to test if I can build my design, as long as they don’t return any error, then the build is successful.

The GitHub actions are based on YAML files, which contain details of the container that the image is being run on, and the commands that are run for that image. These files are stored in the folder .github/workflow in the GitHub repository, I have two, one which runs the Simulation and one which build the FPGA Image.

We will talk though the build firmware Github Action, which I have called Build Firmware. I have decided that this should be run whenever I push the repositry, for Pull requests and on demand. So we define the name of the action, and add the description of when it should be run, the workflow_dispatch allows me to manually trigger it being run.

name: Build Firmware

on:
  push:
  pull_request:
  workflow_dispatch:

With the name, and when the action should be run defined, we move onto defining the action. For my build we need to define the job and the build. For this I am running on Ubuntu Latest as my image.

jobs:
  build:
    runs-on: ubuntu-latest

Now that we have the image we are running on we need to add the dependancies that are required for building out FPGA image. First step is to checkout our repository we are running from with the uses: actions/checkout@v2, which will get our repo using the default settings without any issues. With both Yosys and Next-Pnr needed to build the image, the next step is a little different to what I originally had planned. I thought that I would need to build these tools from source like I would on my own computer, but that is very time consuming, and I came across some pip packages, which installs them much quicker. This reduces build time, which on private repo’s on GitHub are billed after you are passed your allowance.

- uses: actions/checkout@v2
- name: Install the required Tools
run: |
	sudo -H pip3 install yowasp-yosys
	sudo -H pip3 install yowasp-nextpnr-ecp5-25k

One problem I did come across when installing these packages, was that if I ran these pip3 install commands without sudo, then the commands that I need then aren’t available. Running with sudo solves this issue although i’m not sure why.

Now we have all the tools in place we can now run both yosys and nextpnr, using the commands specific to the yowasp-yosys and yowasp-nextpnr packages, which are a little different to the standard commands I would use on my own Laptop.

- name: Run yosys on the files
	run: yowasp-yosys -p 'synth_ecp5 -json top.json' -S firmware/top.v
- name: Run Place and Route
	run: yowasp-nextpnr-ecp5 --25k --package CABGA381 --json top.json --lpf firmware/colorlight.lpf --textcfg out.config

We can then pull all those components into a single FirmwareBuild.yaml file in the .github/workflow folder, which is then run on each push to the repo. The current design is very simple, but runs in a little over 30 seconds for the build, this makes running on each push manageable, but as the firmware design continues to grow, I may look to only run on Pull request.

name: Build Firmware

on:
  push:
  pull_request:
  workflow_dispatch:

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - name: Install the required Tools
        run: |
          sudo -H pip3 install yowasp-yosys
          sudo -H pip3 install yowasp-nextpnr-ecp5-25k          
      - name: Run yosys on the files
        run: yowasp-yosys -p 'synth_ecp5 -json top.json' -S firmware/top.v

      - name: Run Place and Route
        run: yowasp-nextpnr-ecp5 --25k --package CABGA381 --json top.json --lpf firmware/colorlight.lpf --textcfg out.config

The GitHub action for running the simulation is very similar, but instead of pip3 install for the build tools, I require Verilator which is available to install using apt. As the code to run my Verilator tests is identical between how i run it on my computer and in the GitHub action, I just us my make command to run the tests.

name: Simulate Firmware

on:
  push:
  pull_request:
  workflow_dispatch:

jobs:
  test:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v2

      - name: Install Verilator required for the simulation
        run: sudo apt install verilator

      - name: Run the Serial Test
        run: |
          export VINC=/usr/share/verilator/include
          make test-serial          

My next step for the these GitHub Actions, is to look at extracting some statistics from particularly the build process. I’m interested in monitoring the FPGA utilisation and frequency that the design can be run at, being able to see the effect of each pull request would be advantageous for keeping an eye on how well my design is coming together and the effect of different changes.

Built with Hugo
Theme Stack designed by Jimmy