Blog
HardwareRTLVerification

Designing reusable AXI4-Lite IP that drops into someone else's SoC

Reusability in hardware IP is mostly the work around the RTL: single-sourced registers, a contained vendor surface, checkable verification, and vendor-neutral packaging.


Most open hardware IP is written to work in exactly one testbench, on exactly one FPGA, for exactly one person. Making a core reusable — something a stranger can drop into their SoC and trust — is a different discipline, and it lives mostly in the boring parts around the RTL. Here's how I approach it across my IP cores (a UART, an AES engine, an internal logic analyzer, an AXI crossbar).

Single-source the register map

Hand-written control/status registers drift the instant you add a field: the decode, the docs, and the software header disagree, and nobody notices until integration. In my cores the register map is described once — in a small Python generator (gen/regmap.py) — and the AXI4-Lite decode, the documentation table, and the IP-XACT are all emitted from it. One source of truth means the hardware view and the software view cannot fall out of sync.

Contain the vendor-specific surface

Portability isn't "use no vendor primitives" — it's containment. Every design has a couple of places that genuinely need a technology-specific cell: a reset synchronizer, a clock-domain-crossing FIFO, a block RAM. Those live behind a thin rtl/tech/ layer. Everything else is plain, synthesizable SystemVerilog. Retargeting from one FPGA family to another becomes a one-directory change instead of a grep across the whole core.

Make the verification claim checkable

"It works" is not a specification. Each core ships with self-checking Verilator testbenches and a set of SymbiYosys formal properties, so a reviewer has something concrete to run and read. For the AES core that bar is higher: known-answer tests against the FIPS-197 / NIST CAVP vectors, so the claim is bit-exact, not "passed on my machine."

Package it like a product

The last mile is packaging. Each core is shipped as vendor-neutral IP-XACT 1685-2014, so it lands in any integration flow rather than only mine. The goal is simple: someone should be able to add the core to their SoC from a file — never a GUI, never a copy-paste — and have the registers, interfaces, and parameters already described for the tool.

Reusable IP is a contract as much as it is a datapath. Get the contract right and the RTL travels.