A Brief Introduction to AutoFPGA
You may have heard about AutoFPGA. Perhaps you’ve found it on github. Perhaps you’ve read about it on my projects page. Perhaps you had a chance to hear me describe it at ORCONF, 2017 or looked over my slides. It only seems fitting that I should share it with my readers here as well.
Today, therefore, I’d like to discuss why I created AutoFPGA, and some of the problems with the alternatives. I’ll briefly discuss the goals of AutoFPGA, and the license it is released under. When done, I’ll discuss a new project I just created based upon AutoFPGA, which I’m hoping to use in the future to explain how AutoFPGA works.
Why AutoFPGA? The backstory
I started working on AutoFPGA after creating several independent ZipCPU based projects, and getting annoyed that it felt like I kept rebuilding the wheel. Each project needed to have a bus designed for it, it needed to have interrupts defined and assigned, peripherals needed to be integrated, and all these things changed from project to project.
Perhaps an overview of these projects might help make this clear.
The first wishbone based project I worked on was based around Digilent’s Basys3 board. You can see the basic outline of the project in Fig 1, from before I added the ZipCPU to it.
My purpose was to learn about how to do hardware design on my own, without the office support team that I had when I first started learning hardware design. You know, the difference between relying on the experience of other members of your team, versus needing to have that experience yourself?
Since it was my first design as part of Gisselquist Technology, there were a lot of new parts and pieces. To highlight this new work, I’ve outlined it in blue within Fig 1 above. Basically everything was new.
It was on the Basys3 that I first built a flash controller, a UART, a VGA controller, and much more. Eventually, I built the ZipCPU on the Basys3, even though it’s not shown in Fig 1.
However, I wanted to try working on a project that required an FPGA with a small form factor. Previous designs I had worked on involved both a CPU and an FPGA working together, and I was curious to know if I could do all of the work within a bigger FPGA.
I considered the CMod S6, but ultimately chose to try Xess.com’s XuLA2-LX25 board. (I bought the CMod S6 later.) The XuLA2-LX25 had more capability, more logic within its FPGA, had an SD card socket, and even SDRAM memory. In the end, the design looked something like Fig 2.
You can still find the project here, should you be interested in it. It does contain an SD-Card controller, and an SDRAM controller. You can see the other components of the design in Fig 2 above. It was the first full project that I released under an open-source license. (Unfortunately, it’s poorly documented, despite documentation existing for all the components.)
The good news was that, when building the XuLA project, I was able to re-use a lot of the components I had initially built for my Basys3. Still, looking at the amount of stuff in blue, there was still a lot of work involved in building the new design.
I also decided to toy around with the idea of seeing if I could “broadcast” on a local FM channel using the board, as I had seen a friend do with his Raspberry Pi. (It’s always fun to one-up a CPU developer with your FPGA design.) So, I created an WB FM transmitter hack.
While the FM transmission approach worked like a charm, integrating it into the project on a whim and then taking it out later was pretty annoying. There was a lot of work involved, and several files that needed to be changed, and did I get it all done properly? I think you get the idea. If that wasn’t bad enough, what if I wanted to try the design again later, or demonstrate it for others?
When it was time to move forward with my next design, I wanted to try building something in an FPGA, logic limited environment–just to prove that the ZipCPU would work on one of the small architectures it had been built for. Could it really fit in the smallest FPGA development board I could find? So, I bought a CMod S6 featuring a Spartan 6LX4–the smallest FPGA that Xilinx sells in its the Spartan 6 line. The challenge with this design was to make something small.
For this project, I was able to reuse a lot of the components I had already built. Looking in Fig 3, you’ll see only a small amount of development outlined in blue. The biggest challenge to the design was both building the bus logic, and keeping everything small.
This was also the first project I ever built with time-slicing, but that’s another story.
Since I had never worked with DDR3 SDRAM before, I chose to work with Digitlent’s Arty for my next project so that I might learn about it.
The majority of the new work in this design was for the ethernet, the DDR3 SDRAM controller, the OLEDrgb, and the bus (again). (Eventually, I had to shelve DDR3 SDRAM controller, choosing instead to use a Wishbone to AXI4 bridge. There was also a lot of work to raise the clock speed to 200MHz, but since the Xilinx MIG core could only run at 82MHz on the Arty, this work was shelved.)
When it came time to build an HDMI video processor, I chose to use the Nexys Video. By this point in time, I had finally had enough of rebuilding the wheel on every design.
For every design up until that point, I had hand-crafted an interconnect to connect all the components into the design. (This is the horizontal blue line in each of the figures above.) This interconnect would connect components to an internal Wishbone bus, and it would connect interrupts together from the various peripheral components to one of a couple of interrupt controllers. You can see examples of my interconnects for the XuLA2-LX25 here, the CMod S6 here, and the Arty here. Addresses needed to be assigned, interrupts needed to be assigned, they both needed to be documented, and these things were just taking too much of my time.
To make matters worse, anytime I adjusted the number of addresses a specific peripheral might require, I might need to adjust its location in the address space I was creating. This made for a lot of work. As you may recall, I like to access my designs via a bus based external controller from software, and that software needs to know where things are located on the bus. The CPU also needs to know not only where things are located on the bus, but if particular peripherals are a part of the design or not.
I’ve already discussed how annoying this was when (temporarily) integrating the FM transmitter hack into my XuLA2-LX25 SoC design.
The need for a reconfiguration assistant also came up when I was working on my HDMI video design. At the time, I was struggling to understand what was going on within my (broken) HDMI video stream. I had decided that I needed to capture some of the video stream to block RAM via a wishbone scope, after which I was going to read the results back to find out what was going wrong with my design. The problem with this was that video is a memory hog. Therefore, my wishbone scope needed a large block RAM. This meant that I needed to adjust the size of the block RAM that the CPU was using. This necessitated changing the bus interconnect, the CPU loader, the CPU linker script, the simulation driver that will load the CPU into simulated memory, and more—and all of this just to get the results of a one-time Video capture test.
This was why I wanted a capability like AutoFPGA. AutoFPGA simplifies the number of changes that need to be made to a design when reconfiguring it, working like a secretary (not a designer) to automatically connect things together, and then let you know what it did.
Lessons from Other Aggregators
I think I’ve mentioned that I’ve spent a lot of time answering questions on Digilent’s forums. Many students will come to the forum declaring that they want to build a design in Vivado, but what they really mean is that they want to build a design using the graphical design method Vivado supports. Interacting with these individuals has given me a lot of insight into the problems many students are struggling with as they work to create (and debug) their own designs. From my standpoint, it seems like the biggest problem these new FPGA students are struggling with is the graphical design flow that they are so eager to learn.
Why is this?
The design flow hides a lot of configuration detail. It allows you to connect blocks together, but yet each block needs a lot of internal configuration that isn’t immediately visible once configured. It takes a bit of digging to even get at this configuration information.
As an example, I just recently helped one individual who was struggling to get his HDMI video data lined up with his clock. (He didn’t realize this was his problem until it was fixed.) The particular configurations necessary were hidden within both the SelectIO wizard and the clocking wizard, but neither wizard made the users choices available upon a cursory view of the project.
The design flows aren’t textual. You can’t do a “diff” between two designs.
This makes it hard to answer the question of “how is my design different from the example/reference design.”
Indeed, I was actually rather surprised, when I presented AutoFPGA at ORCONF this year that I got cheers when I declared the whole processing flow to be “textual”, and said that you could run it from within a Makefile. (The same audience groaned during another presentation, when that presenter explained that his tool only had a Graphical User Interface (GUI).)
I guess I hadn’t realized how much of a drag many of the modern graphical tools were becoming to the professional designer. This may be because GUIs tend to start up slowly. It may be because GUIs tend to limit your design options to the road most people travel upon. However, for me the problem is twofold: First, a GUI forces me to slow down and use a mouse. Second, building a design can take a lot of work: I like the option of using make to build only those portions of the design that have changed.
It isn’t clear how to place a scope or a probe into such a design, to see and understand what is going on within it. For example, if you have component
Aconnected to component
B, and the output of component
Bis somehow wrong, how shall you know which of the two is misconfigured?
Going back to the individual struggling to get HDMI video working, he didn’t have any clear locations within his design where he could create a tap and see the problem.
Sure, he could examine some wires via Xilinx’s ILA, but what if you need to create an ad-hoc computer program to comprehend the output of the scope? It wasn’t clear how to do this with the proprietary ILA. Without it, it wasn’t clear how to identify where in the processing chain the problem was at.
This, by the way, is one of the reasons that Open Source scopes are so necessary: their measured output values can easily be ingested into your own specialized debugging software to be processed as you see fit.
At one time, when I asked some other users about graphical design methods, an online acquaintance noted that there doesn’t seem to be any way to “take the training wheels off” of these methods, so as to be able to dig down into the nuts and bolts of a design once you were ready to do so.
Finally, the Xilinx toolchain in particular has created a horrendous problem for Digilent’s support staff, in that every new version of Vivado breaks their demonstration projects.
I’m not sure if this is because they rebuild or reconfigure their component libraries from one version to the next, or if it is because they rebuild their TCL scripting interface, or what. Indeed, I’ve struggled with the problem myself when I tried rebuilding my OpenArty design with a newer version of Vivado. The result of my effort was an error so obscure that not even the Xilinx support staff on their forum could identify. (This is why you won’t find any of the Vivado output files/products in the OpenArty repository.)
As a result, I watch students on the Digilent forum struggling to build the example designs provided for them unless they have the exact same version of Vivado. Indeed, telling the student which version of Vivado to use to build an example/demo is a common Digilent support request response.
Wouldn’t you rather be able to separate your component library updates from your tool updates, so that what works with one tool will work with others?
All of this leads me to the conclusion that, if I wanted to create an alternative, it would need to be OpenSource, and it would need to not take any of the design decisions away from the designer: all of the Verilog files would need to be available for view.
Indeed, I wanted something that would generate Verilog (and c++, and Make) project files that I could then inspect and understand–not something that would hide details that would become difficult to debug later.
Any design flow or tool suite that hides “useless” or “irrelevant” details will also hide the location of your bug. (ZipCPU tweet)
AutoFPGA’s Design Goals
My goal for AutoFPGA was simple: to be able to run AutoFPGA with a list of peripherals, and have it automatically connect those peripherals together in a manner prescribed by their configuration files. Indeed, if you look in an example Makefile that calls AutoFPGA, you’ll find a line that just calls AutoFPGA with a list of components.
To keep things simple, I’d like to type “make” in a top level directory, have make recurse as necessary into any sub-directories to process component configuration files, build design files, assemble those files together, and build a project all from one make command.
Okay, so … I don’t know how to do this with the proprietary vendor based tools (yet), and I don’t want to use a broken Tcl toolflow, but I do know how to do this much with both yosys and Verilator.
(No, I’m not saying that Tcl is broken, but rather that many of the tools that use it are–for the reasons discussed above.)
No new language
Further, I don’t really want to create a new language for component interaction and connection. While I understand that other tools exist, such as IP-XACT, MyHDL, or Migen, I didn’t want to require the developer to learn a knew language (XML, Python, FHDL, etc.) in order to interact with AutoFPGA. I also didn’t want to build a compiler. I wanted AutoFPGA to be a product that I could use to create a production system, and I didn’t want to slow down too much to get there.
For this reason, AutoFPGA is primarily a Copy and Paste utility. The configuration files will identify what things need to be copied and pasted where to create the desired output files. As an example, a Quad SPI flash component doesn’t just need to connect to a wishbone bus, it also needs a little bit of tri-state code inserted at the top design level. (It’s actually worse: since the flash clock line is shared with the load circuitry, a special Xilinx
STARTUPE2component is often required at the top design level as well.)
I’ll need to leave it open for debate as to whether or not I created a “new language”, since the configuration files are neither Verilog nor are they C++, and they are definitely not Python. Instead, the files consist of a simple series of “@KEY=VALUE” pairs, where the
VALUEs can take multiple lines–often containing pieces of Verilog or C++ code.
No hidden design components
AutoFPGA just creates text files. Since AutoFPGA is primarily a copy and paste utility, comments within the AutoFPGA configuration files will just get copied into their respective places.
What this means is, when you have a problem with the design of one of your components, you can look back into that components configuration file and see what got copied and adjust it.
While I like to think that AutoFPGA has met all of these goals and more, I’ll leave it to you and time to be the ultimate judge.
If you are wondering if you can legally use AutoFPGA for your project, the answer is that you can. AutoFPGA is a software program licensed under the GPLv3. If you make changes to it, or improve it, I would love to have those changes returned to the AutoFPGA repository for others to use.
This license doesn’t cover your intellectual property, only the AutoFPGA program itself. Indeed, I consider AutoFPGA to be a piece of software similar to a compiler. As a result, AutoFPGA asserts no particular license on the files it creates, or the projects that use it.
Going one step further, all of my
AutoFPGA projects specify their own
license. What I mean is that I require
AutoFPGA created design files to have
a license statement within them. The license statement chosen if specified
by the global
@LEGAL tag, such as you might find in one of my
global configuration files.
AutoFPGA then copies this
into the files it generates–adjusting the filename and project name as
appropriate. Hence while AutoFPGA
is released under GPLv3, I can choose
to release (or not) any project that uses it. Feel free to adjust the
tag to reference the license appropriate for your project.
A Simple AutoFPGA Design
Given all of that as background, I’d like to spend some time introducing AutoFPGA and discussing how to add (or remove) peripherals to(/from) a project. I’ve created a new project, an AutoFPGA Demo, which contains a series of simple peripherals that can easily become a part of any project using AutoFPGA. This should be simple enough for any new student to learn how to build and integrate components together using AutoFPGA.
I have more complicated demonstrations as well, such as the ZBasic project. ZBasic contains a basic ZipCPU, together with some simple peripherals and several bus structures. Once we exhaust the lessons from the basic AutoFPGA Demo project, we may turn there for some more examples to draw demonstrations from.
We’ll use this example project project, as a demonstration over the next couple of posts, showing what can be done with AutoFPGA.
And his disciples asked him, saying, 'Master, who did sin, this man, or his parents, that he was born blind?'