Published on

Register Generation: A Right of Passage

The Situation

We’ve all been there- the software team is frustrated because the register map documentation doesn’t match the FPGA implementation. Why do we always end up here? We need one source of truth… I know… I’ll write a script to do exactly that (or I’ll have the intern do that!) And it starts….

It takes a certain level of system complexity before this kind of problem shows up and you “discover” this need for a solution- your typical college lab assignment is too simple. You begin to feel the acute pain when you’re waist-deep on a project that’s behind and you’re working with other team members. I’ve noticed that solving one or more parts of this hardware-software disconnect becomes a right of passage for many an FPGA and embedded software engineer.

The “Lucky” Ones

Maybe, instead of self-discovering this, you were lucky enough to join an established team that’s been doing FPGA and software development for a while, in which case, you probably already have some tooling to help in this area. In lots of cases, this likely means some kind of home-grown toolkit. In fact, your organization may have multiple tools (developed by many engineers even independently on different teams) that all essentially do the exact same thing: specify your registers, and generate implementation, documentation and even software headers or drivers. These home-grown tools were written in the software language handy for the person implementing it… maybe TCL, or Perl, or C, or …. Some of these tools might be abandoned, or relegated to some obscure design or repository that is still under support, where everyone hopes they never have to touch them again. The tool was written by the intern who has since left, or the Perl greybeard who retired last year. Each of these tools has some kind of input format, maybe a created domain specific language, or maybe based on some “standard” (.xml, .xls, .toml, .json, …), all well intentioned, but how sustainable are these in the long-run?

The “Well-Resourced” Ones

Maybe you’re not that bad off- your team invested in commercial tooling in this area: Semaphore, Magillem, or one of the many others that have come and gone (Denali Blueprint, PDTi’s SpectaReg, etc.) If this is you, you’re either happy with the current solution (great, but the rest of this blog post probably isn’t so relevant to you) or looking for something more flexible. If flexibility is key for you, your existing commercial tools should be able to export to, and import from, SystemRDL even if you’re not already using that as an input format. If this is true, you’re ahead of the game.

Okay, Maybe Not So Simple

As the days, months and years roll by, we realize that this “simple” problem, and worse still, our “simple” solution just isn’t cutting it. How many engineering teams have done this same thing, with minor twists in the input and output formats? I’m know some of my teams have, and I’ve personally embarked on this process at least twice (“I’ll fix it correctly this time….") You start out with something simple, and it grows legs. Bugs and feature requests pour in, you realize your “simple” format now needs a full-blown parser to help deal with the edge cases. You need logging to debug, and nicer error messages so when someone makes a typo, they can actually find and fix the error themselves without having to call you or visit your desk. Now you need a full chip-map, not just a core’s register, or now you have more than one instance of the same core but you have to provide different base addresses.

The benefits of a single source of truth still outweigh the costs, but can we do better?

One Solution

At this point, collectively as engineers, we’ve proliferated too many of these of bespoke tools and I’m just as guilty as the next engineer. Certainly there’s a cost to replacing/modifying existing workflows, but if we’re honest about it, our own custom implementations are just another form of vendor lock-in, but in this case we can’t even cry out to a third-party for support!

In this case, I don’t have a solution to sell you, nor am I involved with any of these tools, but I have some thoughts and suggestions on this topic:

  • First off, we need a standard, supported by multiple tools. Good news! SystemRDL exists already, and the commercial tools above support it.
  • “But I don’t want/can’t justify etc the commercial tools.” Also good news! There’s an open-source permissively-licensed compiler that is being actively maintained. It’s got an understandable data structure (a tree!) and covers a large portion of the SystemRDL spec already. There’s another tool that is also open-source from Juniper and it supports an Juniper-proprietary format as well as SystemRDL.

Open-source benefits

To me, the availability of a maintained, open-source SystemRDL compiler is awesome. What’s even better is that the code is in Python, permissively licensed, well documented, and very readable. The internal data structures make sense and it’s been built to be extensible such that generating output collateral is as easy as walking a tree. It also has hooks for injecting registers into the data structure that didn’t come from a SystemRDL file, which means that it’s possible to re-use some of your existing front-end files and either convert them to systemRDL or just use them directly (with some considerations).

Note: the systemRDL maintainer also figured out a real parser is a good idea so it’s using ANTLR under the hood, but users of the library reap the benefits without having to deal with the complexity.

Do you dislike the generated code from the commercial tools or their limitations? Use the open-source compiler and tune the templates exactly how you like. Do you want more than just .h files for software? Again, make a new template. Do you want to generate templates for a new language (Rust anyone?), again make a new template and focus on iterating the data structure of the design rather than parsing inputs and trying to figure out this stuff. For Rust fans, an even better option might be to, turn your system into an svd and then use something like svd2rust. Think of the possibilities!

The SystemRDL organization on GitHub has a bunch of related projects that leverage the compiler for different use-cases, but watch out for the licensing if that matters for your use-case, they’re not all as permissively licensed as the compiler.

Certainly there are some potential issues with the spec, and the systemrdl compiler isn’t perfect but pull requests are accepted and the maintainers appear to be very responsive.

What About IP-XACT?

I certainly think the clarity and syntax of SystemRDL is much easier to understand than trying to deal with IP-XACT’s XML format, especially if you want to edit and change it. I’d suggest that you find or build a way to support import from IP-XACT to system-rdl and vice-versa of using IP-XACT is desired in your development flow. The SystemRDL organization has just such an example, but again, understand if the code license works for you and your organization.

Conclusion

The SystemRDL standard exists and we should use it. There are both open-source and commercial tools which support this standard, we should use or extend those, and stop it with the custom register definition languages and half-baked parsers.

Next time my project needs a register generation tool, I’m going to think about SystemRDL. I’m also considering what would be required to integrate my existing frontends and templates with the compiler as the core of my own custom tooling. Maybe this can be the stepping stone I need to bridge legacy designs into a new world using the SystemRDL standard.