ZipCPU/autofpga
A utility for Composing FPGA designs from Peripherals
AutoFPGA - An FPGA Design Automation routine
After now having built several FPGA designs, such as the
xulalx25soc,
s6soc,
openarty,
zbasic,
icozip,
and even a Basys-3 design of my own that hasn't been published, I started
recognizing that all of these designs have a lot in common. In particular,
they all have a set of bus masters, such as the
UART-to-wishbone
bridge that I use, the hexbus debugging
bus that offers a simpler version of the same, or even the
zipcpu.
Many of these designs have also started to use (and reuse) many of the
peripherals I've developed, such as
the generic UART,
the QSPI flash controller,
the SD-card controller,
the block RAM controller,
the RMII Ethernet Controller,
the Real-Time Clock, the Real-Time
Date, the
Organic LED controller,
Xilinx's Internal Configuration Access
Port, the wishbone
scope, the GPS controlled
clock,
or even the PWM Audio Controller.
All of these peripherals have a very similar format when included within a
top level design, all of these require a certain amount of care and feeding
as part of that top level design, but yet rebuilding that top level design over
and over just to repeat this information becomes a pain.
Where things were really starting to get annoying is where the C++ information
was depending upon Verilog information. A classic example of this is the
base address of any bus components. However, if you add clock rate into
the mix, you can then also control things such as any default UART
configuration, default clock stepping information (for the RTC clock),
or even default video clock information--just by knowing the FPGA's clock rate
within your C++ environment.
Sharing information between Verilog and C++ then became one of the primary
reasons for creating AutoFPGA. While peripheral address decoding is typically
done in some main Verilog
file,
other files depend upon what this peripheral decoding is. These other files
include the host register definition
file (used
for debugging access), the register naming
file, the
software board definition
file used
by newlib, the linker
script used
by the compiler, and even the LaTeX
specification
for the board. Creating and updating all of these files by hand anytime I
create a new board file can get tedious. Further, every time a board is
reconfigured, the constraints file, whether
XDC or
UCF file, needs
to be updated to match the current constraints.
Solving this multi-language coordination problem is the purpose of AutoFPGA.
Unlike many of the other tools out there, such as Xilinx's board design flow,
AutoFPGA is not built with the clueless beginner in mind, neither is it built
to hide the details of what is going within the project it creates. Instead,
AutoFPGA is built with the sole purpose of alleviating any burden on the FPGA
designer who otherwise has to create and maintain coherency between multiple
design files.
That this program facilitates composing and building new designs from existing
components ... is just a bonus.
Goal
The goal of AutoFPGA is to be able to take a series of bus component
configuration files and to compose a design consisting of the various bus
components, linked together in logic, having an appropriate bus interconnect
and more.
From a user's point of view, one would run AutoFPGA with a list of component
definition files, given on the command line, and to thus be able to generate
(or update?) the various design files discussed above:
- rtl/toplevel.v
- rtl/main.v
- rtl/make.inc
- rtl/iscachable.v -- a function of bus address determining what addresses are cachable and which are not
- sw/host/regdefs.h
- sw/host/regdefs.cpp
- sw/zlib/board.h
- sw/zlib/board.ld
- build.xdc (Created by modifying an existing XDC file. LPF, PCF, and UCF files are also supported)
- sim/verilated/testb.h
- sim/verilated/main_tb.h
- doc/src/(component name).tex (Not started yet)
Specifically, the parser must determine:
-
If any of the components used in the project need to be configured, and if
so, what the configuration parameters are and how they need to be set. For
example, the UART baud rate and RTC and GPS clock steps both need to be set
based upon the actual clock speed of the master clock. Placing a
clock module within the design that sets up a clock and
declares its rate is the current method for accomplishing this. Designs using
more than one clock often have an
allclocks.txt
file to define all of the various clocks used within a design. -
If peripherals have or create interrupts, those need to be found and
determined, and (even better) wired up. -
If an AutoFPGA configuration file describes one of the following classes of
items, then the file is wired up and connected to create the necessary bus
wiring as well.-
Bus masters
Are automatically connected to a crossbar with full access to all of the
slaves on the bus -
One-clock Peripherals (interrupt controller, etc.)
-
Two-clock Peripherals (RTC clock, block RAM, scopes, etc.)
-
Memory Peripherals
o These need a line within the linker script, and they need to define if
their memory region, within that linker script, has read, write, or
-
-
Peripheral files need to be able to describe more than one peripheral. For
example, the GPS peripheral file has a GPS-Clock,
a companion test bench, GPS-TB, to measure the performance of the GPS clock,
and a serial port (WBUART) to allow us
to read from the GPS and to write to it and so configure it. Of course ...
this also includes a parameter that must be set (baud rate) based upon the
global clock rate.
Classes
Some peripherals might exist at multiple locations within a design.
For example, the WBUART serial component can be used to create multiple
serial ports within a design.
To handle this case, the WBUART configuration file may be subclassed within
other component configuration files by defining a key
@INCLUDEFILE=wbuart.txt. This will provide a set of
keys that the current file can then override (inherit from).
Unfortunately, this only works if the included file has only one component
defined within it.
Math
Some peripherals need to be able to perform basic integer math on a given
value to determine an appropriate setting value. These peripherals need
access to variables. The classic examples are the baud rate, which depends
upon the clock rate, as well as the step size necessary for the RTC and the
GPS clocks, both of which also depend upon the master clock rate. Other
examples might include determining the size of the address space to assign
to a core based upon the memory size of the component and so forth.
This feature is currently fully supported using integer math.
Legacy Updates
The original version of AutoFPGA supported only one bus master, one bus type,
and an interconnect with a known bug in it.
Specifically, the broken interconnect would allow a master to make requests
of one peripheral and then another before the first peripheral had responded,
while not preventing the requests from returning out of order.
Fixing this bug introduced several incompatible changes, therefore there is
an AutoFPGA legacy git tag defined to get back to the older version.
This newer version, however, now supports:
-
Multiple bus types: Wishbone (pipelined),
AXI-Lite, and AXIAdditional busses may be supported by simply creating a C++ bus component
definition class for them. -
Full crossbar support, using bus helper files from my WB2AXIP repository.
Much to my surprise, the full crossbar support has proved to be simpler, in
terms of logic elements used, than the legacy interconnect I had been using.
Status
This project now has several designs built around it. These include the
basic AutoFPGA-demo project,
OpenArty,
ArrowZip (legacy AutoFPGA only),
AXI DMA test bench,
ICOZip,
SDR (a gateware defined radio),
ZBasic,
ZipStorm-mx (legacy AutoFGPA only), and
ZipVersa. There's also a rather nice
Nexys Video project that I've used for
modifying and delivering to customers, although the current version on github
is currently a touch out of date. You can see the autogenerated logic generated
for this project in the demo directory.
I've also used AutoFPGA to generate a design for the Cyclone-V on the DE-10
Nano, as well as a design for an Arty Z7-20.
In sum:
-
Simple bus components ... just work. This includes both bus masters and bus
slaves. Not only that, the bus simplifier logic also "just works", with
the caveat below.Note that the AXI SINGLE simplifier itself hasn't (yet) been built. (It's
waiting on a funded need.) For now, the AXI DOUBLE bus
simplifier
should work quite well. To use it, just declare a bus slave to be a slave
of an AXI type bus, with SLAVE.TYPE set to SINGLE, then follow the rule
listed in the
simplifier.
The same applies to the AXI-lite simplifiers. Wishbone simplifiers, both
SINGLE and DOUBLE, are handled by logic inserted intomain.v, rather
than referenced bymain.v. -
Components with logic in the toplevel work nicely as well.
-
AutoFPGA can now support multiple, dissimilar clock rates. Users just need
to specify a clock to generate it. The clock is then made available for
configuration files to reference. This includes creating a test bench
wrapper for Verilator that will drive a multi-clock simulation. -
Addresses get assigned in three groups, and processed in three groups:
simpleSINGLEcomponents having only one address, simpleDOUBLE
components having more addresses but only a single clock delay, and all
other components and memories. -
Multiple bus support is now included, allowing you to create and attach
components through bus adapters. This will allow a request to transition
from one component to the next, while also keeping track of what the final
addresses are for reference from the top level bus.This makes it possible for the SDRAM to be on one bus, supporting video
reads/writes, and for the CPU to be able to access that bus as
well--as a sub-bus of the main peripheral/memory bus. -
Interrupts get assigned to a named controller, and then C++ header files are
updated to reflect the interrupt assignments -
A simple integer mathematical expression evaluator exists, allowing simple
math expressions and print formats. This makes it possible to set a global
clock frequency value, and to then set baud rates and other clock dividers
from it. -
Only one type of address building is supported. I'd like to be able to
support others, but so far this has been sufficient for my first project.o Likewise, the project only supports WB B4/pipelined. No support is
provided for WB B3/classic (yet), although creating such support shoud not
be difficult at all. -
AutoFPGA now builds a ZipCPU Linker Script for the
project. This script is highly configurable, and many of my projects contain
configurations for multiple linker scripts--depending upon which memories
I decide to include in the design, or which ones I want a particular piece of
software to use. -
The LaTeX specification table building isn't there ... yet.
Sample component files
Component files now exist for many of the components I've been using regularly.
These include: a Flash controller,
block RAM, a UART console,
a very simple GPIO controller,
RMII ethernet controller,
MDIO ethernet control interface,
a GPS UART and PPS-driven internal clock,
a Real-Time (GPS driven) Clock,
a PS/2 Mouse,
an OLED component, and more.
Many of these component cores exist and have their own repositories elsewhere.
For example, the wishbone UART core may be found
here, and you can find a MIG-based,
Wishbone controlled SDRAM component
here.
You can also find a AXI examples, such as AXI S2MM stream-to-memory data
mover,
an AXI MM2S memory-to-stream data
mover,
or an AXM block RAM
component
in the AXI DMA test repository.
Building the cores themselves is not a part of this project, but rather
figuring out how to compose multiple cores into a top level design from
both cores and component descriptions.
The ZipCPU blog
Several articles have now been written to date about AutoFPGA on the ZipCPU
blog. These includes:
-
Using AutoFPGA to connect simple registers to a debugging bus
This article is really out of date, in that it describes only the legacy
mode (one master, one bus type, etc.)
Getting Started
The current best reference for AutoFPGA is the icd.txt file,
which describes all of the various tags AutoFPGA understands and how they
can be used. I've also started working on an intermediate
design
tutorial based around AutoFPGA, so you might find that a useful place to start
as well.
License
AutoFPGA is designed for release under the GPLv3 license. The AutoFPGA
generated code is yours, and free to be relicensed as you see fit.
Commercial Applications
Should you find the GPLv3 license insufficient for your needs, other licenses
can be purchased from Gisselquist Technology, LLC. Given that the AutoFPGA
generated code is not encumbered by any license requirements, I really don't
expect any such requests.
Likewise, please contact us should you wish to guide, direct, or otherwise
fund the development of this project. You can contact me at my user name,
dgisselq, at the wonderful ieee.org host.