New Generator: Linear-Feedack Shift Registers

Building on our vision to offer a comprehensive, web-based code generator for FPGA and ASIC developers, we are thrilled to announce the initial rollout of our Linear-Feedback Shift Register (LFSR) generator.

LFSRs are a class of pseudo-random number generators that can be implemented very efficiently in FPGA or ASIC technologies. As you can see in the figure below, a 7-bit LFSR is just a chain of 7 register stages with two XNOR feedback taps at positions 6 and 7. When initialized to zero, and provided with a clock signal, this marvelous little circuit will almost magically cycle through every possible state (except one) of the 7-bit word in a defined sequence that repeats itself every 127 cycles.

The micro-architecture of a 7-bit linear-feedback shift register

LFSRs have a single invalid state which—like a beetle stuck on its back—they cannot exit on their own. For XNOR feedback types LFSRs, the invalid state is all ones. Fortunately, the invalid word is not part of the LFSR’s natural sequence whose length is thus 2N-1 instead of 2N, N being the LFSR length in bits.

In digital electronics, LFSRs are often used to generate Pseudorandom Binary Sequences (PRBS) for testing serial or parallel communication links. PRBS-7 and PRBS-31 are two common kinds of Pseudorandom Binary Sequences, which can be generated respectively with 7-bit and 31-bit LFSRs. In the case of a serial communication link, the bit sequence is obtained from the MSB of the shift register (e.g. Q7 in the diagram above).

Implementing LFSRs in hardware is no rocket science. Still, since it’s not something that developers do every day, it can easily take an hour or two until the proper feedback taps and feedback type have been figured out and the circuit is finally working in simulation and in synthesis.

Using the new LFSR generator in airhdl, you can now design an LFSR in minutes and immediately download the VHDL or SystemVerilog implementation.

The new LFSR view in airhdl.com

For your convenience, airhdl also provides C and Python models of the LFSR so that you can easily display the sequence of numbers that the LFSR will cycle through. This can be super convenient when it comes to comparing numbers recorded with a logic analyzer with the expected sequence.

By default, the Python model outputs the first 16 words of the LFSR sequence in hexadecimal format:

$ python .\prbs7_lfsr.py
00
01
03
07
0F
1F
3F
7E
7D
7B
77
6F
5F
3E
7C
79

Using the optional count argument, you can tell the script how many output words to generate:

$ python .\prbs7_lfsr.py 4
00
01
03
07

The -i option allows you to start the sequence on an arbitrary initial value:

$ python .\prbs7_lfsr.py -i 0x3F 8
3F
7E
7D
7B
77
6F
5F
3E

This way you can easily convince yourself that it’s a very bad idea to initialize the LFSR to all ones (that’s the beetle stuck on its back):

$ python .\prbs7_lfsr.py -i 0x7F 8
7F
7F
7F
7F
7F
7F
7F
7F

We hope you’ll find the new LFSR generator useful and as always, make sure to let us know what you think!

Using the OSVVM AXI4 Verification Components to Simulate an airhdl Register Bank

Back in 2015, when I first attended Jim Lewis’ excellent Advanced VHDL Testbenches & Verification training in Bracknell (England), OSVVM was mostly a collection of VHDL packages that could be used to simplify the task of writing VHDL testbenches. At the time, OSVVM already included things like constrained random stimulus generation, scoreboards, functional coverage, and logging capabilities, but it wasn’t yet a one-stop shop for all your VHDL verification needs.

Fast forward a few years and thanks to Jim’s incredible work, OSVVM has become a world-class VHDL verification framework that is used by professional design teams around the world. Plus, when it comes to AXI4 verification, OSVVM probably has the most comprehensive set of verification components covering the AXI4, AXI4-Lite, and AXI4-Stream protocols.

To show you how simple an OSVVM-style testbench for an AXI4-Lite slave component can be, I have created a small project called osvvm-demo, which you can find on the airhdl GitHub. The testbench, whose architecture is depicted in the diagram below, consists of the following components:

  • The device under test (osvvm_regs), is an airhdl-generated register bank with two registers: a Control register that can be read and written from the bus, and a Status register that can only be read from the bus. I’ve given each of those registers a 16-bit field called value.
  • Axi4LiteManager is an OSVVM Verification Component (OSVVM has many of them) that acts as an AXI4-Lite bus master. It can issue AXI4-Lite read and write transactions to the device under test.
  • The Test Controller is the testbench orchestrator. It remote controls AxiLiteManager, instructing it to issue AXI4-Lite transactions, over a transaction interface that is implemented using record-typed VHDL signals.

Notice that the register bank output port corresponding to the Control register is looped back to the input port which drives the value of the Status register. This makes it very easy to check that both the Control and the Status registers are working as expected, by simply writing a value such as 0x1234 into the Control register and checking that the same value can be read back from the Status register.

Architecture of the osvvm-demo testbench

In a typical OSVVM fashion, there may be different incarnations of the Test Controller component, which OSVVM calls Test Cases, where each test case is implemented as a different architecture of the Test Controller entity. Although our demonstration testbench has only one test case, it’s usually a good idea to have several of them, such as a test case for normal operation and a test case for error conditions. I recommend keeping your test cases simple and focused on one particular aspect of the verification.

Our test case, which is called operation, has a single control process whose source code is shown below. What that process does is wait for initialization and reset to complete, write a magic value (0x1234) to the Control register using the Write procedure, read back the value of the Status register using the Read procedure, and check that both values are matching. When everything is done, it prints out a PASS/FAIL report on the simulator console.

    ControlProc : process
        variable addr           : unsigned(31 downto 0);
        variable wdata          : std_logic_vector(31 downto 0);
        variable rdata          : std_logic_vector(31 downto 0);
        variable actual_value   : std_logic_vector(STATUS_VALUE_BIT_WIDTH - 1 downto 0);
        variable expected_value : std_logic_vector(CONTROL_VALUE_BIT_WIDTH - 1 downto 0);
    begin
        -- Initialization of test
        SetAlertLogName("tb_osvvm_regs_operation");
        SetLogEnable(INFO, TRUE);
        SetLogEnable(DEBUG, FALSE);
        SetLogEnable(PASSED, FALSE);

        -- Wait for testbench initialization 
        wait for 0 ns;

        -- Wait for Design Reset
        wait until nReset = '1';
        ClearAlerts;

        Log("Write Control register");
        addr  := unsigned(REGS_BASEADDR) + CONTROL_OFFSET;
        wdata := x"00001234";
        Write(Axi4MemRec, std_logic_vector(addr), wdata);

        Log("Read Status register");
        Read(Axi4MemRec, std_logic_vector(addr), rdata);

        -- Extract field value from register value
        actual_value   := rdata(STATUS_VALUE_BIT_WIDTH + STATUS_VALUE_BIT_OFFSET - 1 downto STATUS_VALUE_BIT_OFFSET);
        expected_value := wdata(CONTROL_VALUE_BIT_OFFSET + CONTROL_VALUE_BIT_WIDTH - 1 downto CONTROL_VALUE_BIT_OFFSET);

        -- Compare write and read field values
        AffirmIfEqual(expected_value, actual_value, "read data");

        EndOfTestReports;
        std.env.stop;
        wait;
    end process ControlProc;

Notice the procedural and abstract coding style of the Test Case. We are not fiddling with signals here, only calling high-level procedures that do all the underlying protocols and bit-bouncing for us.

When it comes to compiling and simulating the testbench in a VHDL simulator, OSVVM has you covered as well. You can declare your source sets in the form of project (*.pro) files, which can recursively include project files from other directories. The top-level project file for this testbench is RunAllTests.pro.

The beauty of OSVVM project files is that they will work with virtually every capable VHDL simulator, without requiring any simulator-specific Tcl scripting.

To learn more about the OSVVM library, you can visit the OSVVM website or the project’s GitHub.

New Feature: Transfer Register Map Ownership

One of the many benefits of the airhdl Professional plans is the ability to share register maps with other airhdl users, either in a read-only way or with full editing priviledges. Technically, the user who first creates a register map becomes the owner of that register map, and that gives him or her special priviledges, such as being able the share the register map with other users, or to delete the register map from the database.

After a few years of working with airhdl (and possibly switching jobs in between), some of our users have expressed the need to transfer the ownership of one or more register maps to other airhdl users. Until now, that wasn’t possible in the user interface but the latest airhdl release now allows you to do that very easily, provided you have an active Professional subscription.

To transfer ownership of a register map to another airhdl user, click on the gear icon in the Register Map view and select Transfer Ownership in the drop down menu:

This brings up the Transfer Ownership dialog, which prompts you for the e-mail address of the user you’d like to transfer that register map to. The e-mail address should correspond to the one of a registered airhdl user:

Once you’ve entered the e-mail address, click the Transfer Ownership button to trigger the transfer.

Note that transferring ownership of a register map cannot be undone. Please make sure to double-check the e-mail address of the destination user before clicking the Transfer Ownership button.

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:

REG_0
REG_1
REG_2

REG_99

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 regs2json.py, is available on our GitHub page. It can be used as follows:

python regs2user.py 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 regs2json.py 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 airhdl.com 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 my_regs.md

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

pandoc -o my_regs.pdf my_regs.md

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:

2020-04-26_9-22-07

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.