A XactFlow importer plugin that reads a SystemVerilog
module plus a JSON metadata file (and, optionally, a SystemRDL register map) and adds the
ipxact.Component it describes to a XactFlow Library, built on
ipxact-compiler's
IEEE 1685-2022 object model.
ipxact-compiler parses IP-XACT and hands back Python objects; XactFlow's Importer interface
is for the other direction, reading some non-IP-XACT source and adding that object model to a
Library. This package is one such importer: it does not write XML itself, turning the
resulting Component into a file is a separate exporter's job (see
xactflow-component).
The SystemVerilog parsing and metadata-driven design was informed by
ipxact-sv2ipxact, an earlier, experimental
standalone tool that solves a closely related problem by writing IP-XACT XML directly. This
package is a from-scratch implementation built against ipxact-compiler's object model rather
than a fork of it, and its scope, dependencies, and error handling are its own.
pip install xactflow-svFor local development, requirements-dev.txt overrides ipxact-compiler and xactflow to
local installations. It can be modified to adapt the paths or to keep either version on PyPI.
pip install -r requirements-dev.txt -e .Requires Python >= 3.9. Runtime dependencies beyond ipxact-compiler/xactflow:
pyslang for SystemVerilog parsing, and
systemrdl-compiler/
peakrdl-ipxact for register map conversion.
An importer's job stops at adding an ipxact.Component to a XactFlow Library, as a target
(target=True); it does not write anything out on its own, so getting an actual IP-XACT XML
file also needs an exporter, like
xactflow-component. Once both are installed,
the importer registers itself under the xactflow.importers entry point group as sv, so
it can run as one XactFlow CLI command, --then handing the same library straight to the
exporter in the same process:
xactflow sv my_module.sv --option metadata=my_module_ipxact.json --then component --output out/
# writes out/<vendor>_<library>_<name>_<version>.xml--lib DIR adds the IP-XACT files under DIR to the library, e.g. the bus definitions the
component refers to. The component is regenerated from its source, so it replaces a document of
the same VLNV found there (replace=True), such as the output of a previous run, instead of
being reported as an SCR 1.1 duplicate VLNV.
Or as a library, e.g. to inspect or modify the Component before exporting it:
from pathlib import Path
import ipxact
from xactflow import Library
from xactflow_sv import SVImporter
from xactflow_component import ComponentExporter
library = Library() # or Library.scan("path/to/ip/library")
SVImporter().import_(Path("my_module.sv"), library, metadata="my_module_ipxact.json")
(component,) = library.targets(ipxact.Component)
component.vlnv # VLNV
component.model.ports # list[Port]
component.bus_interfaces # list[BusInterface]
component.memory_maps # list[MemoryMap]
ComponentExporter().export(library, Path("out")) # writes out/<vendor>_<library>_<name>_<version>.xmlOnly the module's parameters and ports are read (from its header, and its body parameters when it has no parameter port list), with no elaboration, no package loading, no symbol resolution: types, values, and dimension expressions are taken verbatim from the source text, matching how IP-XACT's own expression model treats them.
- VLNV: vendor, library and version from the metadata file, name from the module.
- Model: one view
rtlreferencing one component instantiation<module>_rtl, withlanguagesystemverilogandmoduleNamethe module name. - Parameters: each overridable SV parameter gives a component
parameter(withparameterIdandresolve="user", holding the default value) and amoduleParameterwhose value references thatparameterId, so a design override reaches the HDL module. ThemoduleParameter'sdataTypeis the SV type as written (int,logic [7:0],typefor a type parameter, ...), and unpacked dimensions becomearrayson both. - Ports:
- a vector or scalar port is a
wireport, its packed dimensions giving thevectors. Built-in integer types get their width, e.g.intgives[31:0]; - a struct/typedef-typed port is a
structuredport of typestruct, with the type name instructPortTypeDefs(its width is not known without elaboration); - an SV
interfaceport is astructuredport of typeinterface, with the interface name and its modport as role; - unpacked dimensions become
arrays,[N]giving[(N)-1:0].
- a vector or scalar port is a
- Bus interfaces and memory maps: from the metadata file, see below.
A small JSON file supplies what can't be inferred from the SV source alone:
{
"vendor": "Vendor",
"library": "Library",
"version": "1.0",
"busInterfaces": {
"apb": {
"bus": "Vendor:Library:apb4:1.0",
"mode": "target",
"ports": {"PSEL": "psel", "PADDR": "bus_req_i.paddr"},
"memoryMap": "register_map_mmap"
}
},
"registerFile": "register_map.rdl"
}-
vendor/libraryare required,versiondefaults to"1.0". The component'snamealways comes from the parsed module name, not from this file. -
busInterfacesmaps a bus interface name to its bus VLNV, mode, and either aportsmapping of logical bus signal names onto physical SV port names, or aninterfacePortnaming a genuine SVinterface-typed port that already groups its own signals. Aportsvalue can be a plain port name or a dottedport.fieldreference into a struct-typed port (e.g.bus_req_i.paddr). For aportsmapping, the abstraction definition is derived by convention as<bus-def-name>_rtlat the same vendor/library/version asbus. Everyinterface-typed port in the module must be described this way; there is no fallback guess for its bus VLNV or mode. -
modeis one of (case-insensitive):mode also accepted extra keys initiatormastertargetslavememoryMap(optional)systemgroup(required)mirroredInitiatormirroredMastermirroredTargetmirroredSlavemirroredSystemgroup(required)monitormonitoredMode(required),group(required ifmonitoredModeis a system mode)groupis the system group name from the bus definition.monitoredModeis the mode of the interface the monitor watches, any mode butmonitor. -
memoryMapnames the memory map a target interface gives access to. When the component has exactly one target interface and one memory map, that target references it by default. -
registerFileis a path (absolute, or relative to the metadata file) to a SystemRDL file describing the component's register map. It is compiled withsystemrdl-compiler, converted withpeakrdl-ipxact, and merged in as the component'smemory_maps. Its memory map is named<addrmap name>_mmap.
Any other key, at the top level or in a busInterfaces entry, raises a ValueError, so a
misspelled key is not silently ignored.
Given as --option name=value on the CLI, or as keyword arguments to import_, after the
library:
metadata(required): path to the metadata file.define: preprocessor symbols to predefine before parsing,--option define=SYM1,SYM2=4on the CLI ordefine=["SYM1", "SYM2=4"]in Python.include: directories to search for`includefiles, in addition to the.svfile's own directory,--option include=rtl/include,rtl/pkgorinclude=["rtl/include", ...].module: name of the module to import. Required when the file declares more than one module.
Paths given in options are relative to the current directory. Any SystemVerilog error
reported while parsing (syntax error, include file not found, unknown macro) raises a
ValueError with its file and line, instead of importing a partially parsed module.
- Four independent stages, each targeting
ipxact-compilerdataclasses directly rather than XML:sv_parser.pyreads the module's parameters and ports into plain dicts,component_builder.pyturns those intoipxact.Port/ipxact.Parameter/the component'sModel,bus_interfaces.pybuildsipxact.BusInterfacefrom the metadata'sbusInterfaces, andregister_map.pybuildsipxact.MemoryMapfrom a SystemRDL file. register_map.pyreadspeakrdl-ipxact's own XML output, not throughipxact-compiler's parser.peakrdl-ipxactonly supports IEEE 1685-2014, whileipxact-compileronly supports IEEE 1685-2022. A namespace swap alone would silently lose that data (a field's access policy, or a register's array dimensions, would just come back empty rather than erroring), so a dedicated reader is used instead. This is a keep-it-simple choice for now, maybe not permanent, see Ideas for later.- Fails loudly instead of silently dropping data. Constructs this package does not yet
support (see below) raise
NotImplementedError/ValueErrorrather than producing aComponentthat quietly leaves something out.
- Explicit ANSI ports (
.name(expr)syntax) and non-ANSI port lists (module m(a, b); input a; ...) are not supported. Only implicit ANSI-style ports are. A direction-less first port defaults toinout, per the SystemVerilog LRM. - Only
[left:right]dimensions are supported, plus the[N]size shorthand on an unpacked dimension. Indexed part-selects ([base+:width]/[base-:width]), queues ([$]), dynamic arrays ([]) and a zero size ([0]) raise an error. - Ports with a data type that has no bit width are not supported:
real,shortreal,realtime,string,chandle,event. Built-in integer types get their width as a vector, e.g.intgives[31:0]andbytegives[7:0]. - A parameter without a default value is not supported (
parameter int Norparameter type Twith no= ...), as there is no value to give the component parameter. Parameters are read from the parameter port list (#(...)), or from the module body when the module has none,localparams being skipped, per the SystemVerilog LRM. - Register/register file arrays are not supported.
- A
registerFiledefining anaddrmapthat is never used under the chosen top-leveladdrmapis rejected, rather than silently ignored as SystemRDL itself would. A reusable sub-blockaddrmapinstantiated under a real top is unaffected. - A register/field/register file/address block with
ispresent = falseis not supported. IEEE 1685-2022 has no equivalent ofisPresent, so there is no way to represent one as conditionally absent rather than silently promoting it to always-present. - A SystemRDL construct
peakrdl-ipxactcannot export at all raises an error, e.g. amemnode nested inside another node's hierarchy, rather than silently producing an incomplete memory map. fileSetsare not generated. The component never records which.svfile the module actually came from.
- Have
register_map.pybuild onipxact-compiler's own parser instead of its own ElementTree reader. Not a quick swap:peakrdl-ipxactonly emits IEEE 1685-2014 XML, andipxact-compiler's parser expects 2022's structure for field access and array dimensions (see Design notes). Feeding it 2014 XML after only a namespace fix-up parses without error but silently comes back missing that data, confirmed by testing it directly. Doing this properly needs a 2014-to-2022 XML restructuring step first (in this package, not inipxact-compiler, which is a 1685-2022 parser by design), or forpeakrdl-ipxactto gain 2022 output support upstream.
LGPL-3.0. See LICENSE.