How to Import 100 Registers from a Text File to airhdl

One of our users recently asked how he could import a list of 100 registers into airhdl without having to create every single register by hand in the user interface. He had the names of the registers available in a text file, one name per line:



Subscribers to the airhdl Professional CL plan can import register maps into airhdl by uploading a JSON file whose structure is described in the documentation.

To help import the user’s registers into airhdl, we have created a small Python script that transforms the user’s text file into an airhdl register map JSON object. The script, which is called, is available on our GitHub page. It can be used as follows:

python registers.txt map_name

Where registers.txt is the path to the text file containing the register names and map_name is the name of the register map to be created. The script generates an output file called out.json in the current working directory, which looks like this:

  "jsonVersion": 2,
  "registerMap": {
    "name": "my_map",
    "description": "",
    "width": 32,
    "baseAddress": 0,
    "addrWidthBits": 32,
    "revision": 1,
    "generateRecordPorts": false,
    "registers": [
        "type": "Register",
        "name": "REG_0",
        "description": "",
        "access": "READ_WRITE",
        "addressOffset": 0,
        "size": 32,
        "fields": [
            "name": "value",
            "description": "",
            "bitWidth": 32,
            "bitOffset": 0,
            "reset": 0,
            "selfClear": false

The last step is to upload the generated out.json file to the airhdl web application using the Upload button in the Register Maps view:

This creates a new register map with the name that we have specified when executing the script (in this example, my_map):

The out.json file can also be used as an input to the airhdl command line generator, which can generate all the airhdl output products (VHDL and SystemVerilog RTL code, testbenches, C header and documentation) locally on the user’s machine:

java -jar airhdl-cl.jar out.json

As we have seen, all it takes is a few lines of Python code to turn a text file into an airhdl register map JSON object that can be either uploaded to the airhdl web application to create a new register map, or used locally as an input to the airhdl command line generator.

Shiny and New: the SPI to AXI4-Lite Bridge

Following a user request, we have created an open-source SPI to AXI4-Lite bridge which allows you to access register banks generated by from any microcontroller over a Serial Peripheral Interface (SPI).

SPI to AXI4-Lite Bridge

The bridge is available in both VHDL and SystemVerilog versions, and comes as a single, self-contained file with no additional dependencies. It supports all four combinations of SPI clock phases and polarities, also known as SPI modes.

The source-code repository includes a VHDL testbench that was developed using the Open-Source VHDL Verification Methodology (OSVVM). The simulation requires a VHDL-2008 capable simulator such as Aldec Riviera-Pro.

We are releasing the SPI to AXI4-Lite bridge under a permissive Apache License 2.0, which allows you to use it in commercial applications.

Please feel free to try it out and let us know what you think!

Using airhdl in a Master Class System on Chip Design

A while ago, I stumbled across airhdl thanks to a colleague from the university
(KU Leuven, Belgium). I instantly loved the simplicity and intuitively that the tool provides. Because of this, airhdl is now incorporated in my lessons System on Chip (SoC) design that are taught to the master students in Electrical Engineering and the European master in Radiation and its Effects on MicroElectronics and Photonics Technologies (RADMEP for short).

The approach of the labs is simple… Don’t use old dusty books and practices but instead, teach the students how it is done in the industry. Therefore, a real environment how it should be done in a design/verification team is emulated and yes, also the verification part. Thus, sending a single stimulus in the DUT and call it a day is of course out of order 😉!

The exercise is in essence the same, year over year (but the RTL design/verification and software development are different). Students design and verify an IP according to specifications. Verification of the IP is done via testing frameworks such as UVM, Vunit, cocotb, pyuvm, …. Once the IP is verified, it is packaged and then integrated in the Zynq SoC from Xilinx. Afterwards application software is written, and system-level debugging is performed to ensure correct behavior of the complete system.

The IP itself is of such complexity that a wide range of configuration and event registers are used in the design. On top of this, multiple memories are also instantiated and used in the design. All these registers and memories are, of course memory mapped, and this is where airhdl comes in to play.

Students use airhdl to keep their register management in line. They create their register map via the tool and use the auto generation features to generate the RTL and import it in their IP project. I noticed that they didn’t have any problem of understanding and using airhdl as a tool. A small demonstration along my side was more than sufficient so that they could start with their tasks. Therefore, I think that airhdl is also a suitable tool for academic purposes and teach students in electrical engineering how register mapping is done. I hope this inspires more professors/lecturers to use airhdl in their classes.

Levi Mariën is a System on Chip design and Verification Engineer at Nokia (Fixed Networks) and lecturer at the KU Leuven (Belgium) where he teaches a master class System-on-Chip Design to the Electrical Engineering students and the students in Radiation and its Effects on MicroElectronics and Photonics Technologies (RADMEP).

How to initialize 30,000 coefficients over AXI4 using airhdl (and a bit of custom logic)

One of our airhdl users recently asked how he could use an airhdl-generated register bank to initialize the 30,000 (or so) weights of a neural network circuit.

When dealing with such large numbers of coefficients, it’s not practical to create a dedicated addressable register for every coefficient as the corresponding logic becomes too large and and slow. What you can do instead is to either store them in a memory, which is very efficient in terms of logic resources, or in a register chain in case you need to concurrent access to the coefficients.

The memory option is quite straightforward as airhdl allows you to create memory-typed register map elements, which you can connect to a block memory components as shown in this article. The downside of this option is that you can only access one element at a time from the user logic.

In the register chain option, the coefficients are stored in the flip-flops of a large shift register, which gives you concurrent access to all of the elements. To implement the register chain, you will first need to create a write-only register (e.g. weight) with a value field corresponding to the width of your coefficients (e.g. 10 bits):

Consequently, the following user output ports are exposed in the generated RTL component:

weight_strobepulsed every time a new value is written to the weight register
weight_valuethe current value of the weight.value register field

You then connect those ports to the input of a 30,000-deep shift register that is part of the user logic, with the weight_strobe acting as a clock-enable to the shift register. To initialize the shift register and thus your coefficients, all you have to do is write the 30,000 coefficients in a row over the AXI4 interface to the weight register using a fixed address pattern. Make sure not to use an incrementing address pattern as there is really only one adressable register in the register bank.

One issue you may run into while implementing this circuit is the high fanout on the weight_strobe signal, which can cause excessive delays and thus timing violations. Here are two ideas to improve the situation:

  • Split the register chain into several smaller chain, each connected to a dedicated register.
  • Route the weight_strobe net through a global buffer like a Xilinx BUFG or BUFR. This adds a fixed delay to the net but in exchange the signal can then be distributed with low skew to a large number of cells.

We hope you will find this useful. To stay informed about what’s going on at airhdl, please follow us on twitter or on LinkedIn.

New Feature: Auto-Compute Register Offsets

Following several user requests, airhdl now offers a way to auto-compute the register offsets within a register map. By clicking the Auto-compute register offsets button, airhdl automatically re-computes the address offsets of all the registers in the register map, starting at zero, and ensuring that there are no address gaps between them.

Auto-compute register offsets button

We hope you’ll find this feature useful. If you use airhdl, please make sure check out our Feature Requests board where you can submit new ideas for improvement and/or vote for existing proposals.

New Feature: Markdown Generator

Following a user request, airhdl is introducing a new a Markdown documentation generator. You can now choose to download your register map documentation in either HTML or Markdown formats:

In case you haven’t come across Markdown before, it’s lightweight, text-based markup format that was initially proposed by John Gruber. You can find a description of the Markdown syntax here.

Markdown being such a popular markup language, it is well supported by source code editors such as Visual Studio Code or Eclipse. Besides that, there are many other tools for processing Markdown documents.

For example, you can use the Python grip package to render a Markdown document in a web browser:

python grip

Or you can use pandoc to convert a Markdown document to a PDF file:

pandoc -o my_regs.pdf

We hope that you’ll find the new Markdown documentation generator useful!

New Feature: Enumerated Values

Upon popular request, airhdl now supports enumerated values for register fields.

Enumerated values are a convenient was to give names to specific field values. As an example, we’ll take a two-bit mode field that is used to control a processing engine. This field supports the following values:

• 0: disabled
• 1: manual
• 2: automatic

To edit a field’s enumerated values, bring-up the Edit Field dialog and activate the Enumerated Values tab:

For each enumerated value, enter the name and the corresponding value in the input fields and click Add:

When you’re done entering all enumerated values for a field, click Save Field:

Once you have done that, airhdl knows about those values and corresponding symbols appear in the generated files. For example, in the generated C header, you’ll find them as preprocessor defines:


Of course, your enumerated values are available in the generated RTL code (VHDL and SystemVerilog) as constants too.

We hope you’ll find them useful.

New Feature: the Register Calculator

Calculating a register’s value from the values of its fields, or vice-versa, can be a tedious and error-prone task. It’s often a time where we developers have to pull out a sheet of paper and draw some diagrams in order to get it right.

In our quest to make your life as a developer easier, we’re introducing a new tool to airhdl called the Register Calculator. It’s available for every register created in airhdl: to start it just click on the calculator icon in the register overview:


This brings up the Register Calculator in a pop-up window where you’ll see a graphical representation of the register, along with an input field for every register field and an input field for the total register value. Changing the value of a field updates the total register value (at the bottom). And as you would expect, changing the register value updates the field values as well.


In the top right corner of the window, a radix selector lets you choose between the three usual radixes (hexadecimal, decimal and binary). The selected radix applies to all fields in the window.

Next to the register value field, three helper buttons are available for the following actions:

  • Clear the register (set all fields to zero)
  • Reset the register (set all fields to their reset value)
  • Copy the register value to the clipboard

We hope you’ll like it!

New Feature: Register Map Sharing

As a first step towards the goal of enabling true collaborative work between team members, airhdl now supports sharing register maps in a read-only way. This means that any airhdl user with a Professional subscription (which is just $199 per year or $16 per month) can now share his/her register maps with any other airhdl user. The recipient will have the right to view the shared register map, and to generate the corresponding files.

Let’s have a look at how to actually share a register map in airhdl.

At the bottom of the register map overview, you’ll notice a new “Sharing” section. To share the current register map, click on the “+ Share” link at the bottom of the table.


Then, in the “Share Register Map” dialog, enter the e-mail address of the user with whom you’d like to share (please make sure to enter the e-mail address that the user actually uses to log-in to airhdl), and click the Share button.


The newly created permission then appears in the sharing table:


When the recipient user logs in, the register map will appear in his list of register maps, in the “Shared Register Maps” section:



New Feature: Memory Interfaces

Upon popular request, airhdl now supports a new kind of register map element called a “memory interface”. Unlike the “register” and “register array” elements, a memory interface does not generate storage elements in the register bank. Instead, it allows you to connect an external SRAM to the register bank using a simple address and data bus, and to access that SRAM from the bus as if it were an array of registers.

Memory interfaces support the following access modes: read-write, write-only and read-only. While a read-write memory can be read and written from the bus,  a write-only memory can only be written from the bus (which can be useful for elements like look-up tables that must be writable by software and readable from the user logic).

To add a memory interface to an existing register map, click the “+ Memory” icon at the bottom of the registers list:


This brings up the new memory dialog, which, in addition to the usual information, asks you for the memory depth (in elements). Each memory element occupies the same number of bytes as a single register in the memory map (4 bytes). For example, a memory with a depth of 16 will occupy 64 bytes in the memory map. The first element is accessible at the memory’s base address, while the last one resides at offset 15 · 4 = 60 from the memory’s base address.

Now let’s have a look at how to actually connect a memory to the register bank. Assuming a read-write memory interface, airhdl will generate the following user ports for the memory:

• *_addr is the read and write address
• *_wdata is the write data bus
• *_wen is the (byte-wide) write-enable signal
• *_rdata is the read data bus

Memory writes are performed by asserting the *_wen signals while outputting the write address on the *_addr port and the write data on the *_wdata port.


Memory reads assume a sychronous RAM with a read latency of one clock cycle:


• on rising edge #2, the register bank outputs the address
• on rising edge #3, the SRAM is expected to output the corresponding data
• on rising edge #4, the register bank registers the read data on the *_rdata port

Please feel free to give memory interfaces a try, and let us know what you think.