Adding support to a new FPGA board on Chisel sample project using FuseSoc

This post originated from a live-tweed. The thread can be seen at https://twitter.com/carlosedp/status/1382057618114494465.

I'll show here how to add support for a new board, the Digilent ArtyA7, a very popular FPGA board based on Xilinx Artix7, to my Chisel ChiselBlinky project including FuseSoc support.

Chisel is an HDL (Hardware Design Language) based on Scala that provides more abstractions and the power of a fully-featured language to generate hardware.

FuseSoc is a package manager and generator for FPGA designs. With FuseSoc you can instantiate modules and define how each design will be generated on a multitude of FPGA backends. Usually each FPGA vendor has it's own tool (called EDA) and have a very particular way of defining how things are done. FuseSoc abstracts most of this for you.

ChiselBlinky is a demo project I made as a learning exercise and a template for new Chisel projects. It's just a simple module that blinks three LED s based on a clock and has a reset button.

Disclaimer: I’ve never used Xilinx FPGAs and Vivado before and will discover how to use it as I go.

Requirements

Blinky expects five IO pins, a clock input, a reset button and three leds.
The clock is fed into a PLL to generate a 25Mhz output. The PLL is a blackbox that wraps a vendor PLL IP Verilog source added to the resources folder. I made it in a way that the file can be dynamically defined based on a parameter.

The Toplevel module

Here is the PLL blackbox module:

import chisel3._
import chisel3.util._
class PLL0(board: String) extends BlackBox with HasBlackBoxResource {
val io = IO(new Bundle() {
val clki = Input(Clock())
val clko = Output(Clock());
val lock = Output(Clock())
})
addResource("/pll_" + board + ".v")
}

ChiselBlink expects the PLL Verilog to live in the src/main/resources dir named as “pll_boardname.v”. We will get to it soon.

The first thing is getting which pins to use. It’s called IO Constraints. Since Arty is a nicely documented board, I’ll grab the ArtyA7 35T master constraint file from @DigilentInc Github.
We’ll use the pins:
Clock: E3
Reset: D9 (btn0)
Led0: H5
Led1: J5
Led2: T9

Here we have the constraints file:

For IO, Chisel expects the pins to have “io_” prefix as can be seen on the LEDs. Clock and reset are not prepended.

We will call this board artya7–35t. I could open Vivado, browse it’s IP library to generate the PLL but since I’m lazy, I’ll try to borrow an existing PLL Verilog from CoreScore and change the output clock. The Arty has a 100Mhz oscillator onboard. From what I see, the PLL divides the clock by 100 and multiplies by 16 (for CoreScore). I’ll change the multiplier to 25 (that is what my design expects) and adjust module and pin names.

Now we have all required changes to be able to generate the Verilog code from our Chisel HLD. Both Toplevel.v and our PLL are in the ‘generated’ output dir.

./scripts/mill toplevel.run -td generated -board artya7-35t

Check-out the screencast below for the generation demo:

Now lets add FuseSoc support to generate our project. The project already has a chiselblinky.core file which defines the requirements for another boards. It’s a matter of changing three sections, [filesets], the static files that must be part of the project(only the IO constraints in this case), [generate] which is the chisel-generator that generates Verilog from Chisel and the [targets] which contains the target boards to generate. It has the EDA tool (Vivado) and FPGA part used on this board. Also it’s where we link it all together the required filesets and generators.

In the generator section, we have listed the files our Chisel generator outputs. Here it’s the Toplevel.v with Topmodule and Blinky modules and another file with the PLL module. Since we used a blackbox, Chisel creates a separate Verilog file for it. We need to add both.

When run, FuseSoc will copy our files to a working directory, generate the output files and copy to its output the files we listed (in filesets and generators). These are the files that the EDA tool will use.

First lets create the FuseSoc project, add the libraries (both Fusesoc-cores that contains the generator and the local library with chiselblinky). If you don’t have FuseSoc, the ChiselBlinky readme has a quick explanation.


In the end we have the complete project to be opened on Vivado.

mkdir chiselblinky-test && cd chiselblinky-test# First lets add the fusesoc-cores library containing the generator
fusesoc library add fusesoc-cores https://github.com/fusesoc/fusesoc-cores
# Now I'll add a locally managed source library that contains the changes we did
fusesoc library add chiselblinky $HOME/repos/chisel-playground/blinky
# we can list the available cores
fusesoc core list |grep blink
# and check which boards are supported by the project
fusesoc core show carlosedp:demo:chiselblinky
# And generate the project for the Arty board
fusesoc run --target=artya7-35t --setup carlosedp:demo:chiselblinky

Below is a screencast of the project generation:

And we have the Vivado files ready for use. I run with the --setup parameter so FuseSoc does not call Vivado for me since it’s not installed on my computer. If I use it on a Linux with Vivado installed, it would do most steps automatically.

Since Vivado supports Windows and Linux and I’m on a Mac, I’m going to use a Windows 10 VM (it’s a VirtualBox VM so I can share folders between my Mac host and it) to run Vivado steps manually. It’s also a great way to learn and explore it.

I’ll open a command prompt and load Vivado environment variables. Then I’ll go to my project directory containing the files.

To create the Vivado project I’ll run the command:
vivado -notrace -mode batch -source carlosedp_demo_chiselblinky_0.tcl. Then I’ll open the resulting file with Vivado GUI with:
vivado carlosedp_demo_chiselblinky_0.xpr

If I was running on Linux, the Makefile would automate this.

Lets run the Synthesis using the play button on the toolbar. When finished, Vivado will ask me what to do next. I chose “Run Implementation”.

Just as a heads-up, since I’m running this on a VM, I used USB Passthru to pass my board that is connected thru USB to the VM via the toolbar setting in VirtualBox.

During the synthesis, I got an error. Probably my laziness and PLL strategy didn’t work out as expected. Let’s fix this.

That’s a great opportunity to learn how to use the Clocking Wizard, a tool that generates clock devices for Xilinx FPGAs. Our parameters are Input 100Mhz, output 25Mhz, no need for reset out, create a lock output.

Clocking options
Output clocks

With a lot more Verilog code, we have our PLL. I cleaned it up in the file that was committed later on.

Let’s re-run the whole FuseSoc run step to generate the files and load into Vivado.

Success, now let’s generate the bitstream. Vivado prints some stats for my design in the bottom. It currently uses 8 LUT and 25 FlipFlops 😃

After Bitstream is done, we should open the Hardware Manager, open the target (choose auto-connect) and program the board. Some nice sensor stats shown as well.

Weirdly enough, Vivado doesn’t “auto-fill” the generated bitstream. I had to manually find it oncarlosedp_demo_chiselblinky_0.runs/impl_1/Toplevel.bit

And there we have it, blinking. One minor gotcha is that this board switches are not inverted logic so I’ll add handling this case to my Toplevel module via a parameter. Here in the video I’m holding the reset button.

The full code is in this commit:

As can be seen, adding support for the new board is easy and straightforward.

I highly recommend the Arty A7 board since there is a lot of documentation and support for it online.

If you have any feedback or questions, please get in touch on Twitter.

Writing everything cloud and all the tech behind it. If you like my projects and would like to support me, check my Patreon on https://www.patreon.com/carlosedp

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store