Default registers
Many projects use a few default registers in standard locations that shall be present in
all modules.
For example, very commonly the first register of a module is an interrupt status register and the
second one is an interrupt mask.
In order to handle this, without having to duplicate names and descriptions in many places, there
is a default_registers
flag to the from_toml()
function.
Passing a list of Register
objects will insert these registers first in
the RegisterList
.
Usage in TOML
The TOML file below is used to showcase insertion of default registers.
1# Adapt the "interrupt_status" default register for the needs of this register list.
2[interrupt_status]
3
4# The "mode" property MUST NOT be present for a default register.
5# The mode of the register is set in the default register object in Python.
6
7# The "description" property is OPTIONAL for a default register.
8# If specified, it will only be set in this register list, not other register lists that also
9# use this default register.
10# If not specified, the description of the default register object in Python will be used.
11description = "Interrupt status for my module."
12
13# Register fields can be added freely to a default register.
14# Will only be added to this register list, not other register lists that also use
15# this default register.
16overflow.type = "bit"
17overflow.description = "Too high data rate."
18
19underflow.type = "bit"
20underflow.description = "Too low data rate."
21
22# Note that the "interrupt_mask" default register is not adapted here.
23# It will be included in this register list at its default configuration.
24
25# Further registers and register arrays can be added freely after the default registers.
26[config]
27
28mode = "r_w"
29description = "Generic configuration register."
Usage with Python API
The Python code below shows
How to parse the TOML file listed above.
How to create an identical register list when instead using the Python API.
How to generate register artifacts.
Note that the result of the create_from_api
call is identical to that of the
parse_toml
call.
Meaning that using a TOML file or using the Python API is completely equivalent.
You choose yourself which method you want to use in your code base.
1# Standard libraries
2import sys
3from pathlib import Path
4
5# First party libraries
6from hdl_registers.generator.c.header import CHeaderGenerator
7from hdl_registers.generator.cpp.interface import CppInterfaceGenerator
8from hdl_registers.generator.html.page import HtmlPageGenerator
9from hdl_registers.generator.vhdl.register_package import VhdlRegisterPackageGenerator
10from hdl_registers.parser.toml import from_toml
11from hdl_registers.register import Register
12from hdl_registers.register_list import RegisterList
13from hdl_registers.register_modes import REGISTER_MODES
14
15THIS_DIR = Path(__file__).parent
16
17
18DEFAULT_REGISTERS = [
19 Register(
20 name="interrupt_status",
21 index=0,
22 mode=REGISTER_MODES["r_wpulse"],
23 description="Interrupt status. Clear interrupt(s) by writing the corresponding bitmask.",
24 ),
25 Register(
26 name="interrupt_mask",
27 index=1,
28 mode=REGISTER_MODES["r_w"],
29 description="Enable or disable interrupts by setting bitmask.",
30 ),
31]
32
33
34def parse_toml() -> RegisterList:
35 """
36 Create the register list by parsing a TOML data file.
37 """
38 return from_toml(
39 name="caesar",
40 toml_file=THIS_DIR.parent / "toml" / "basic_feature_default_registers.toml",
41 default_registers=DEFAULT_REGISTERS,
42 )
43
44
45def create_from_api() -> RegisterList:
46 """
47 Alternative method: Create the register list by using the Python API.
48 """
49 register_list = RegisterList.from_default_registers(
50 name="caesar", source_definition_file=None, default_registers=DEFAULT_REGISTERS
51 )
52
53 interrupt_status = register_list.get_register(register_name="interrupt_status")
54 interrupt_status.description = "Interrupt status for my module."
55 interrupt_status.append_bit(
56 name="overflow", description="Too high data rate.", default_value="0"
57 )
58 interrupt_status.append_bit(
59 name="underflow", description="Too low data rate.", default_value="0"
60 )
61
62 register_list.append_register(
63 name="config", mode=REGISTER_MODES["r_w"], description="Generic configuration register."
64 )
65
66 return register_list
67
68
69def generate(register_list: RegisterList, output_folder: Path):
70 """
71 Generate the artifacts that we are interested in.
72 """
73 CHeaderGenerator(register_list=register_list, output_folder=output_folder).create()
74 CppInterfaceGenerator(register_list=register_list, output_folder=output_folder).create()
75 HtmlPageGenerator(register_list=register_list, output_folder=output_folder).create()
76 VhdlRegisterPackageGenerator(register_list=register_list, output_folder=output_folder).create()
77
78
79def main(output_folder: Path):
80 generate(register_list=parse_toml(), output_folder=output_folder / "toml")
81 generate(register_list=create_from_api(), output_folder=output_folder / "api")
82
83
84if __name__ == "__main__":
85 main(output_folder=Path(sys.argv[1]))
See RegisterList.from_default_registers()
for more Python API details.
Generated code
See below for a description of the code that can be generated when using register arrays.
HTML page
See HTML file below for the human-readable documentation that is produced by the
generate()
call in the Python example above.
See HTML code generator for more details about the HTML generator and its capabilities.
VHDL package
The VHDL code below is produced by the generate()
call in the Python example above.
Click the button to expand and view the code.
See VHDL code generator for instructions on how it can be used in your VHDL project.
C++ interface header
The C++ interface header code below is produced by the generate()
call in
the Python example above.
Click the button to expand and view the code.
C header
The C code below is produced by the generate()
call in the Python example above.
Click the button to expand and view the code.