OSHWA and the FOSSi Foundation have teamed up to provide guidance for those of you who would like to share FPGA/HDL designs under an open-source paradigm in an efficient way, enabling others to reproduce your work, use it, modify it and feed back improvements. We are making no assumptions regarding your level of proficiency in FPGA design. If you already have some experience, feel free to skip over the quick intro and nomenclature sections.
A quick introduction to FPGAs
Field Programmable Gate Arrays (FPGA) are an important part of many hardware designs. An FPGA is a chip which can be configured to perform any logic function within the limits of its resources and the ability of the designer.
The inside of an FPGA can be very loosely described as a “sea” of configurable gates, flip-flops and interconnect. In the old days, designers used chips from e.g. the 7400-series to design a Printed Circuit Board (PCB) which would carry out a given logic function. This was cumbersome and inflexible. A change of functionality often required a modification of the PCB and long delays to wait for manufacturing. With FPGAs, changes in functionality which don’t affect the pinout do not need a redesign of the PCB. You just reconfigure the FPGA with an appropriate bitstream.
The following is by no means meant as normative. It is just a list of terms you may read in these guidelines or elsewhere, with their most commonly accepted meaning. I.e., this section is only meant to help you navigate the world of FPGA design if you are new to it.
When a designer writes HDL code they are not “programming”, but actually “describing” a circuit. This is what the ‘D’ in HDL stands for. Different statements and blocks in HDL describe different parts of a circuit. A piece of circuit does not “happen” before or after another one. They just exist at the same time in different parts of the FPGA silicon. Therefore, we don’t use words like “execute” for a bitstream, because they convey some kind of sequential running of instructions as in software. For similar reasons, some prefer configuring an FPGA (i.e., loading a bitstream) to programming an FPGA, although the latter is very much used as well.
Some of the HDL you can write is not synthesizable, meaning that there is no clear circuit equivalent to it. These non-synthesizable HDL constructs (for example instructions to read and write from a file) are typically used for writing testbenches, which are used during simulation in a computer. The synthesizable part of HDL is sometimes referred to as RTL (Register Transfer Level) code, although strictly speaking you can write synthesizable HDL which is not RTL.
An increasing number of people use the word “gateware” to refer to HDL code, in particular RTL. This is in reaction to the use of the term “firmware” for RTL. Why do we need a new word? Well, imagine a situation in which you designed a PCIe board which contains an FPGA. The PCIe board is hosted in a PC running GNU/Linux, and you communicate with it using Linux device drivers, libraries and programs. These drivers, libraries and programs fall squarely under the software heading. Now imagine your board also contains a small microcontroller running bare-metal (no operating system) code. There would be broad consensus to call this code firmware. An increasingly popular practice in FPGA design is to describe a processor in HDL, using some of the gates and flip-flops in the FPGA to “create” that processor. Now if you need to distinguish the HDL code that implements the processor from the code running in it, you may want to avoid using the word firmware for both. This is where a word like gateware comes in handy. In short, whenever you read “gateware” you can interpret it to mean “HDL code” or “RTL code”.
The design itself
OK, so you would like to share your FPGA design with the world. Here are some recommendations:
- If you want to make your design portable across FPGA brands and families, try to write it in a Hardware Description Language and avoid using, as far as possible, design input methods which are only available in a proprietary tool such as those supplied by the FPGA vendors. Also, if you cannot avoid instantiating technology-specific blocks, isolate these instantiations as much as possible to facilitate porting to other technologies, including other FPGA families or even Application-Specific Integrated Circuits (ASICs).
- Because HDL files are text files, they lend themselves easily to include a licensing header. Make sure all your files include such a header. This is no different to the case of licensing software source files, so best practices such as those described in the REUSE guidelines can be useful. See the section on licensing below for a good choice of licenses that can be safely used with gateware.
- You may be sharing a complete FPGA design (maybe to complete the open-source release of a PCB containing an FPGA) or a reusable HDL block (also sometimes called an IP Block or an IP Core, or just a Core). Make sure what you are sharing is clearly described in the documentation.
- If you are releasing a Core, make sure the recipients of the code can easily replicate your work, use it in their designs and modify it as needed.
Important ancillary components
Releasing the RTL of your core or complete design is not enough. You can make the life of others wanting to use your HDL much easier if you also provide:
- Testbenches. This is a must for any high-quality design. A designer feeds the RTL and testbenches (typically also written in HDL) to a simulator, and can gain reassurance that things will work before deploying on the field. Sometimes simulation is automated through scripts, in which case of course the scripts should be included, along with any necessary documentation. Simulation is part of the broader topic of verification. In highly complex HDL designs, verification is a work package from day one, sometimes requiring more effort than the design itself.
- Scripts to generate macro blocks or cores from an FPGA vendor. There are typically graphical tools to generate these, included in the FPGA design tools, but there can still be good reasons to provide external scripts for automating this generation. One reason could be licensing: you may not have the right to distribute the proprietary cores along with your open-source code. Providing scripts allows the user to generate these cores locally without the need of any distribution of proprietary components. Automatic generation scripts also tend to be more robust than graphical tools for ensuring that your design works well across version changes in the toolchain.
- Synthesis scripts and/or instructions. Synthesis is the first stage in the conversion of your RTL into a bitstream. It takes in HDL sources and generates a netlist using primitives provided by the FPGA vendor. Synthesis tools typically accept many options. For complete top-level designs, some people provide the synthesis configuration file, while others automate everything using scripts. Both methods have their merits, and a bit of documentation explaining how to synthesize a given design never hurts. Constraints for synthesis can also apply to a single Core.
- Place & Route scripts and/or instructions. Place & Route is the second step towards bitstream generation. It takes in the netlist produced by the synthesis tool and finds appropriate places in the FPGA to host each bit of logic. Then it interconnects everything together using the configurable interconnect in the FPGA. The discussion about synthesis above applies fully in regards to what to join to your published project. As in the case of synthesis, this applies mainly to top-level designs, but some P&R constraints could also apply to a single Core. Many people just include the “project file(s)” used by a given design tool from an FPGA vendor, which embed all synthesis and P&R options, as well as directives for bitstream generation.
- Packaging. Complex FPGA designs are typically composed of a number of interconnected Cores. Some of these Cores can actually have other Cores inside. This is not unlike the situation in software, where you have libraries that are used to make a program, and those libraries might depend on other libraries. A relatively recent development in FPGA design consists of managing Cores in a similar way that package managers (e.g. in GNU/Linux) manage libraries and other software components. A separate file, called a core description file, helps these managers understand the Core interface and dependencies, and prepare it to be used with different Electronic Design Automation (EDA) tools. If you are releasing a Core, it is good to consider releasing a core description file along with it. See the tools section below for one possible way of doing this.
- Documentation. This is where you tell the world what you have done, why this or that part of the design is done that way, how to contribute fixes and improvements, etc. A good design manual and user manual are signs of high-quality design. Documentation can also include examples of use of your Core, timing diagrams of its interfaces and instructions on how to use any test programs (also to be released if applicable) to talk with your design once in the FPGA.
Whether you use proprietary or Free and Open Source Software (FOSS) tools for your FPGA designs, chances are that users will need to use the same tools. Below is a non-exhaustive list of tools, each with a list of extensions for files you may want to share (beyond your design sources) to make life easier for those who want to use your designs:
- FuseSoC: .core (Core description files)
- Intel Quartus Prime: .qpf (project file), .qsf (settings), .sdc (constraints), .qsys (IP descriptions)
- Microsemi Libero Design Suite: .prj (project file), .pds (pinout constraints), .sdc (other constraints)
- ModelSim / Questasim: modelsim.ini (configuration), .tcl (script files)
- Synplify: .sdc (constraints), .tcl (script files)
- Xilinx ISE Design suite: .xise (project file), .ucf and/or .xcf (constraints).
- Xilinx Vivado: .xdc (constraints), .xci / .xcix (IP core), .bd (block diagram), .bxml, .tcl, .xpr (project file).
- Yosys: tcl (script files)
Of course if you are going through all this effort to share your work, you should make sure you grant all the users of your HDL appropriate rights to use, modify and republish your code, and to make products based on it and distribute those products. This is very important, and a fact which is sometimes not fully appreciated: the default for copyright is “all rights reserved”, so unless you explicitly grant these permissions through a license, people cannot copy, modify and republish your work. Putting your code somewhere in a public server is not enough.
As in the case of software, you have three options:
- Permissive licensing. If you choose this licensing regime, users of your Core will be able to modify it and not share modifications back, as well as use it in a proprietary design. A popular modern option for this type of license in the software world, also used for HDL, is Apache v2. If you feel uneasy about the software-oriented language in Apache and would like a similar license but with terms you can more easily relate to in the HDL domain, you are in luck: the Solderpad v2.1 license capitalizes on Apache 2 and only changes terms where it can bring more clarity for hardware and gateware designs. Finally, the CERN Open Hardware License v2 comes in three variants, and one of them, CERN-OHL-P-2.0, is permissive. The effects of these three licenses are very similar, and blocks using them can be easily combined with one another in a single design.
- Weakly reciprocal licensing. In this licensing regime, modifications to your blocks have to be released under the same license, therefore ensuring improvements by users of your HDL are fed back to the community. A design released under a weakly reciprocal license can be used in a larger design without releasing the sources of the larger design though. CERN-OHL-W-2.0, the weakly reciprocal variant of CERN OHL v2, was specifically drafted with this use case in mind. Some designers use weakly reciprocal licenses from the software world in their HDL designs, such as LGPL and MPL v2. If you use them, make sure they cater for the specificities of your HDL design, in particular if you are using proprietary blocks from the FPGA vendor in your design. The use of these licenses was widespread in the past because no suitable weakly-reciprocal license for HDL existed. The CERN OHL v2 W variant filled that gap.
- Strongly reciprocal licensing. In this licensing regime, if your design gets used in a larger design, the complete sources for the larger design need to be released under the same strongly reciprocal license. The most popular option in this regime for software is GPL, but it suffers from a number of shortcomings when used for HDL. In particular, you cannot use proprietary blocks provided by the FPGA vendor in your design, which is often the case for top-level FPGA designs. Even if you are just releasing a Core, this restriction would apply to everyone using your Core in a top-level design. To cope with this and other issues, the CERN OHL v2 includes a strongly reciprocal variant, CERN-OHL-S-2.0, which ensures sharing back of large designs using your block while taking into account the realities of the FPGA design ecosystem. In some situations, you may want to license under GPL for good reasons, e.g. to be able to combine your work with other GPL-licensed work. In that case we recommend dual-licensing your design, under both GPL and CERN-OHL-S-2.0.
Any software sources in your project should be released under appropriate free and open-source software licenses, approved by OSI and/or the FSF. Similarly, documentation should be released under appropriate documentation licenses such as CC0, CC-BY or CC-BY-SA.
The above are just some guidelines to help you share your FPGA designs effectively. If you have any questions, for example regarding how these apply in your particular context, you can ask them in the OSHWA forums. Happy sharing!