Register arrays

A register list, i.e. the register set of one module, can contain register arrays. Meaning, a set of registers within the register list that are repeated a number of times.

This page will show you how to set up register arrays, and will showcase all the code that can be generated from it.

Usage in TOML

The TOML file below shows how to set up a register array. See comments for rules about the different properties.

TOML that sets up a register array.
 1[base_addresses]
 2
 3# The "type" property MUST be present and set to "register_array".
 4type = "register_array"
 5
 6# The "array_length" property MUST be present for a register array.
 7# The value specified MUST be a positive integer.
 8# The registers within the array will be repeated this many times.
 9array_length = 3
10
11# The "description" property is OPTIONAL for a register array.
12# Will default to "" if not specified.
13# The value specified MUST be a string.
14description = "One set of base addresses for each feature."
15
16
17# ------------------------------------------------------------------------------
18# This will allocate a register "read_address" in the "base_addresses" array.
19[base_addresses.read_address]
20
21# Registers in a register array follow the exact same rules as "plain" registers.
22# The properties that MUST be set or are OPTIONAL are the same.
23# Just as with plain registers, the "type" property can be left out or explicitly set to "register".
24# Fields (bits, bit vectors, ...) can be added to array registers in the same way.
25mode = "r_w"
26
27# This will allocate a bit vector field named "address" in the "read_address" register within
28# the "base_addresses" array.
29address.type = "bit_vector"
30address.width = 28
31address.description = "Read address for a 256 MiB address space."
32
33
34# ------------------------------------------------------------------------------
35[base_addresses.write_address]
36
37mode = "r_w"
38
39address.type = "bit_vector"
40address.width = 28
41address.description = "Write address for a 256 MiB address space."

Below you will see how you can parse this TOML file and generate artifacts from it.

Usage with Python API

The Python code below shows

  1. How to parse the TOML file listed above.

  2. How to create an identical register list when instead using the Python API.

  3. 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.

Python code that sets up a register array.
 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.implementation import CppImplementationGenerator
 8from hdl_registers.generator.cpp.interface import CppInterfaceGenerator
 9from hdl_registers.generator.html.page import HtmlPageGenerator
10from hdl_registers.generator.vhdl.record_package import VhdlRecordPackageGenerator
11from hdl_registers.generator.vhdl.register_package import VhdlRegisterPackageGenerator
12from hdl_registers.parser.toml import from_toml
13from hdl_registers.register_list import RegisterList
14from hdl_registers.register_modes import REGISTER_MODES
15
16THIS_DIR = Path(__file__).parent
17
18
19def parse_toml() -> RegisterList:
20    """
21    Create the register list by parsing a TOML data file.
22    """
23    return from_toml(
24        name="caesar",
25        toml_file=THIS_DIR.parent / "toml" / "basic_feature_register_array.toml",
26    )
27
28
29def create_from_api() -> RegisterList:
30    """
31    Alternative method: Create the register list by using the Python API.
32    """
33    register_list = RegisterList(name="caesar")
34
35    register_array = register_list.append_register_array(
36        name="base_addresses", length=3, description="One set of base addresses for each feature."
37    )
38
39    register = register_array.append_register(
40        name="read_address", mode=REGISTER_MODES["r_w"], description=""
41    )
42
43    register.append_bit_vector(
44        name="address",
45        description="Read address for a 256 MiB address space.",
46        width=28,
47        default_value="0000000000000000000000000000",
48    )
49
50    register = register_array.append_register(
51        name="write_address", mode=REGISTER_MODES["r_w"], description=""
52    )
53
54    register.append_bit_vector(
55        name="address",
56        description="Write address for a 256 MiB address space.",
57        width=28,
58        default_value="0000000000000000000000000000",
59    )
60
61    return register_list
62
63
64def generate(register_list: RegisterList, output_folder: Path):
65    """
66    Generate the artifacts that we are interested in.
67    """
68    CHeaderGenerator(register_list=register_list, output_folder=output_folder).create()
69
70    CppImplementationGenerator(register_list=register_list, output_folder=output_folder).create()
71    CppInterfaceGenerator(register_list=register_list, output_folder=output_folder).create()
72
73    HtmlPageGenerator(register_list=register_list, output_folder=output_folder).create()
74
75    VhdlRegisterPackageGenerator(register_list=register_list, output_folder=output_folder).create()
76    VhdlRecordPackageGenerator(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.append_register_array() 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.

HTML page

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.

Base register package

Note how the register indexes are functions here, as opposed to constants as they usually are for plain registers. The argument to the function decides which array index to use. There is an assertion that the array index argument does not exceed the number of times the register array is repeated.

Click to expand/collapse code.
Generated VHDL register package.
  1-- -----------------------------------------------------------------------------
  2-- This file is automatically generated by hdl-registers version 7.0.2-dev.
  3-- Code generator VhdlRegisterPackageGenerator version 2.0.0.
  4-- Generated 2025-01-21 20:52 at commit 3c3e6c67d817.
  5-- Register hash d398508c05f52d1800bf8d33954a99a6ebc864d8.
  6-- -----------------------------------------------------------------------------
  7
  8library ieee;
  9use ieee.std_logic_1164.all;
 10use ieee.numeric_std.all;
 11use ieee.fixed_pkg.all;
 12
 13library register_file;
 14use register_file.register_file_pkg.all;
 15
 16
 17package caesar_regs_pkg is
 18
 19  -- ---------------------------------------------------------------------------
 20  -- The valid range of register indexes.
 21  subtype caesar_register_range is natural range 0 to 5;
 22
 23  -- ---------------------------------------------------------------------------
 24  -- The number of bits needed to address all 6 registers on a register bus.
 25  -- Note that this figure includes the lowest two address bits that are assumed zero, since
 26  -- registers are 32-bit and unaligned accesses are not supported.
 27  constant caesar_address_width : positive := 5;
 28
 29  -- Number of times the 'base_addresses' register array is repeated.
 30  constant caesar_base_addresses_array_length : natural := 3;
 31  -- Range for indexing 'base_addresses' register array repetitions.
 32  subtype caesar_base_addresses_range is natural range 0 to 2;
 33
 34  -- Register indexes, within the list of registers.
 35  function caesar_base_addresses_read_address(
 36    array_index : caesar_base_addresses_range
 37  ) return caesar_register_range;
 38  function caesar_base_addresses_write_address(
 39    array_index : caesar_base_addresses_range
 40  ) return caesar_register_range;
 41
 42  -- Declare 'register_map' and 'regs_init' constants here but define them in
 43  -- the package body (deferred constants).
 44  -- So that functions have been elaborated when they are called.
 45  -- Needed for ModelSim compilation to pass.
 46
 47  -- To be used as the 'registers' generic of 'axi_lite_register_file.vhd'.
 48  constant caesar_register_map : register_definition_vec_t(caesar_register_range);
 49
 50  -- To be used for the 'regs_up' and 'regs_down' ports of 'axi_lite_register_file.vhd'.
 51  subtype caesar_regs_t is register_vec_t(caesar_register_range);
 52  -- To be used as the 'default_values' generic of 'axi_lite_register_file.vhd'.
 53  constant caesar_regs_init : caesar_regs_t;
 54
 55  -- To be used for the 'reg_was_read' and 'reg_was_written' ports of 'axi_lite_register_file.vhd'.
 56  subtype caesar_reg_was_accessed_t is std_ulogic_vector(caesar_register_range);
 57
 58  -- -----------------------------------------------------------------------------
 59  -- Fields in the 'read_address' register within the 'base_addresses' register array.
 60  -- Range of the 'address' field.
 61  subtype caesar_base_addresses_read_address_address is natural range 27 downto 0;
 62  -- Width of the 'address' field.
 63  constant caesar_base_addresses_read_address_address_width : positive := 28;
 64  -- Type for the 'address' field.
 65  subtype caesar_base_addresses_read_address_address_t is u_unsigned(27 downto 0);
 66  -- Default value of the 'address' field.
 67  constant caesar_base_addresses_read_address_address_init : caesar_base_addresses_read_address_address_t := "0000000000000000000000000000";
 68
 69  -- -----------------------------------------------------------------------------
 70  -- Fields in the 'write_address' register within the 'base_addresses' register array.
 71  -- Range of the 'address' field.
 72  subtype caesar_base_addresses_write_address_address is natural range 27 downto 0;
 73  -- Width of the 'address' field.
 74  constant caesar_base_addresses_write_address_address_width : positive := 28;
 75  -- Type for the 'address' field.
 76  subtype caesar_base_addresses_write_address_address_t is u_unsigned(27 downto 0);
 77  -- Default value of the 'address' field.
 78  constant caesar_base_addresses_write_address_address_init : caesar_base_addresses_write_address_address_t := "0000000000000000000000000000";
 79
 80end package;
 81
 82package body caesar_regs_pkg is
 83
 84  function caesar_base_addresses_read_address(
 85    array_index : caesar_base_addresses_range
 86  ) return caesar_register_range is
 87  begin
 88    return 0 + array_index * 2 + 0;
 89  end function;
 90
 91  function caesar_base_addresses_write_address(
 92    array_index : caesar_base_addresses_range
 93  ) return caesar_register_range is
 94  begin
 95    return 0 + array_index * 2 + 1;
 96  end function;
 97
 98  constant caesar_register_map : register_definition_vec_t(caesar_register_range) := (
 99    0 => (index => caesar_base_addresses_read_address(0), mode => r_w, utilized_width => 28),
100    1 => (index => caesar_base_addresses_write_address(0), mode => r_w, utilized_width => 28),
101    2 => (index => caesar_base_addresses_read_address(1), mode => r_w, utilized_width => 28),
102    3 => (index => caesar_base_addresses_write_address(1), mode => r_w, utilized_width => 28),
103    4 => (index => caesar_base_addresses_read_address(2), mode => r_w, utilized_width => 28),
104    5 => (index => caesar_base_addresses_write_address(2), mode => r_w, utilized_width => 28)
105  );
106
107  constant caesar_regs_init : caesar_regs_t := (
108    0 => "00000000000000000000000000000000",
109    1 => "00000000000000000000000000000000",
110    2 => "00000000000000000000000000000000",
111    3 => "00000000000000000000000000000000",
112    4 => "00000000000000000000000000000000",
113    5 => "00000000000000000000000000000000"
114  );
115
116end package body;

Record package

The record package is quite hard to understand in this example, but lets try:

  • The caesar_regs_down_t type is a record with a member base_addresses, which is the name of the register array.

  • The type of this member is a ranged array of another record with two members: read_address and write_address, which are the names of the registers in the array.

  • Both of these are of a record type that contain the address bit vector field set up in this example.

So in our VHDL code we can access a field value for example like this:

job.address <= regs_down.base_addresses[1].read_address.address;
Click to expand/collapse code.
Generated VHDL record package.
  1-- -----------------------------------------------------------------------------
  2-- This file is automatically generated by hdl-registers version 7.0.2-dev.
  3-- Code generator VhdlRecordPackageGenerator version 1.0.0.
  4-- Generated 2025-01-21 20:52 at commit 3c3e6c67d817.
  5-- Register hash d398508c05f52d1800bf8d33954a99a6ebc864d8.
  6-- -----------------------------------------------------------------------------
  7
  8library ieee;
  9use ieee.fixed_pkg.all;
 10use ieee.std_logic_1164.all;
 11use ieee.numeric_std.all;
 12
 13library register_file;
 14use register_file.register_file_pkg.register_t;
 15
 16use work.caesar_regs_pkg.all;
 17
 18
 19package caesar_register_record_pkg is
 20
 21  -- -----------------------------------------------------------------------------
 22  -- Record with correctly-typed members for each field in each register.
 23  -- Fields in the 'read_address' register within the 'base_addresses' register array as a record.
 24  type caesar_base_addresses_read_address_t is record
 25    address : caesar_base_addresses_read_address_address_t;
 26  end record;
 27  -- Default value for the 'read_address' register within the 'base_addresses' register array as a record.
 28  constant caesar_base_addresses_read_address_init : caesar_base_addresses_read_address_t := (
 29    address => caesar_base_addresses_read_address_address_init
 30  );
 31  -- Convert a record of the 'read_address' register within the 'base_addresses' register array to SLV.
 32  function to_slv(data : caesar_base_addresses_read_address_t) return register_t;
 33  -- Convert an SLV register value to the record for the 'read_address' register within the 'base_addresses' register array.
 34  function to_caesar_base_addresses_read_address(data : register_t) return caesar_base_addresses_read_address_t;
 35
 36  -- Fields in the 'write_address' register within the 'base_addresses' register array as a record.
 37  type caesar_base_addresses_write_address_t is record
 38    address : caesar_base_addresses_write_address_address_t;
 39  end record;
 40  -- Default value for the 'write_address' register within the 'base_addresses' register array as a record.
 41  constant caesar_base_addresses_write_address_init : caesar_base_addresses_write_address_t := (
 42    address => caesar_base_addresses_write_address_address_init
 43  );
 44  -- Convert a record of the 'write_address' register within the 'base_addresses' register array to SLV.
 45  function to_slv(data : caesar_base_addresses_write_address_t) return register_t;
 46  -- Convert an SLV register value to the record for the 'write_address' register within the 'base_addresses' register array.
 47  function to_caesar_base_addresses_write_address(data : register_t) return caesar_base_addresses_write_address_t;
 48
 49  -- -----------------------------------------------------------------------------
 50  -- Below is a record with correctly typed and ranged members for all registers, register arrays
 51  -- and fields that are in the 'down' direction.
 52  -- But first, records for the registers of each register array the are in the 'down' direction.
 53  -- Registers of the 'base_addresses' array that are in the 'down' direction.
 54  type caesar_base_addresses_down_t is record
 55    read_address : caesar_base_addresses_read_address_t;
 56    write_address : caesar_base_addresses_write_address_t;
 57  end record;
 58  -- Default value of the above record.
 59  constant caesar_base_addresses_down_init : caesar_base_addresses_down_t := (
 60    read_address => caesar_base_addresses_read_address_init,
 61    write_address => caesar_base_addresses_write_address_init
 62  );
 63  -- VHDL array of the above record, ranged per the length of the 'base_addresses' register array.
 64  type caesar_base_addresses_down_vec_t is array (0 to 2) of caesar_base_addresses_down_t;
 65
 66  -- Record with everything in the 'down' direction.
 67  type caesar_regs_down_t is record
 68    base_addresses : caesar_base_addresses_down_vec_t;
 69  end record;
 70  -- Default value of the above record.
 71  constant caesar_regs_down_init : caesar_regs_down_t := (
 72    base_addresses => (others => caesar_base_addresses_down_init)
 73  );
 74  -- Convert SLV register list to record with everything in the 'down' direction.
 75  function to_caesar_regs_down(data : caesar_regs_t) return caesar_regs_down_t;
 76
 77  -- ---------------------------------------------------------------------------
 78  -- Below is a record with a status bit for each readable register in the register list.
 79  -- It can be used for the 'reg_was_read' port of a register file wrapper.
 80  -- One status bit for each readable register in the 'base_addresses' register array.
 81  type caesar_base_addresses_was_read_t is record
 82    read_address : std_ulogic;
 83    write_address : std_ulogic;
 84  end record;
 85  -- Default value of the above record.
 86  constant caesar_base_addresses_was_read_init : caesar_base_addresses_was_read_t := (others => '0');
 87  -- Vector of the above record, ranged per the length of the 'base_addresses' register array.
 88  type caesar_base_addresses_was_read_vec_t is array (0 to 2) of caesar_base_addresses_was_read_t;
 89
 90  -- Combined status mask record for all readable register.
 91  type caesar_reg_was_read_t is record
 92    base_addresses : caesar_base_addresses_was_read_vec_t;
 93  end record;
 94  -- Default value for the above record.
 95  constant caesar_reg_was_read_init : caesar_reg_was_read_t := (
 96    base_addresses => (others => caesar_base_addresses_was_read_init)
 97  );
 98  -- Convert an SLV 'reg_was_read' from generic register file to the record above.
 99  function to_caesar_reg_was_read(
100    data : caesar_reg_was_accessed_t
101  ) return caesar_reg_was_read_t;
102
103  -- ---------------------------------------------------------------------------
104  -- Below is a record with a status bit for each writeable register in the register list.
105  -- It can be used for the 'reg_was_written' port of a register file wrapper.
106  -- One status bit for each writeable register in the 'base_addresses' register array.
107  type caesar_base_addresses_was_written_t is record
108    read_address : std_ulogic;
109    write_address : std_ulogic;
110  end record;
111  -- Default value of the above record.
112  constant caesar_base_addresses_was_written_init : caesar_base_addresses_was_written_t := (others => '0');
113  -- Vector of the above record, ranged per the length of the 'base_addresses' register array.
114  type caesar_base_addresses_was_written_vec_t is array (0 to 2) of caesar_base_addresses_was_written_t;
115
116  -- Combined status mask record for all writeable register.
117  type caesar_reg_was_written_t is record
118    base_addresses : caesar_base_addresses_was_written_vec_t;
119  end record;
120  -- Default value for the above record.
121  constant caesar_reg_was_written_init : caesar_reg_was_written_t := (
122    base_addresses => (others => caesar_base_addresses_was_written_init)
123  );
124  -- Convert an SLV 'reg_was_written' from generic register file to the record above.
125  function to_caesar_reg_was_written(
126    data : caesar_reg_was_accessed_t
127  ) return caesar_reg_was_written_t;
128
129end package;
130
131package body caesar_register_record_pkg is
132
133  function to_slv(data : caesar_base_addresses_read_address_t) return register_t is
134    variable result : register_t := (others => '-');
135  begin
136    result(caesar_base_addresses_read_address_address) := std_ulogic_vector(data.address);
137
138    return result;
139  end function;
140
141  function to_caesar_base_addresses_read_address(data : register_t) return caesar_base_addresses_read_address_t is
142    variable result : caesar_base_addresses_read_address_t := caesar_base_addresses_read_address_init;
143  begin
144    result.address := caesar_base_addresses_read_address_address_t(data(caesar_base_addresses_read_address_address));
145
146    return result;
147  end function;
148
149  function to_slv(data : caesar_base_addresses_write_address_t) return register_t is
150    variable result : register_t := (others => '-');
151  begin
152    result(caesar_base_addresses_write_address_address) := std_ulogic_vector(data.address);
153
154    return result;
155  end function;
156
157  function to_caesar_base_addresses_write_address(data : register_t) return caesar_base_addresses_write_address_t is
158    variable result : caesar_base_addresses_write_address_t := caesar_base_addresses_write_address_init;
159  begin
160    result.address := caesar_base_addresses_write_address_address_t(data(caesar_base_addresses_write_address_address));
161
162    return result;
163  end function;
164
165  function to_caesar_regs_down(data : caesar_regs_t) return caesar_regs_down_t is
166    variable result : caesar_regs_down_t := caesar_regs_down_init;
167  begin
168    result.base_addresses(0).read_address := to_caesar_base_addresses_read_address(data(caesar_base_addresses_read_address(0)));
169    result.base_addresses(1).read_address := to_caesar_base_addresses_read_address(data(caesar_base_addresses_read_address(1)));
170    result.base_addresses(2).read_address := to_caesar_base_addresses_read_address(data(caesar_base_addresses_read_address(2)));
171    result.base_addresses(0).write_address := to_caesar_base_addresses_write_address(data(caesar_base_addresses_write_address(0)));
172    result.base_addresses(1).write_address := to_caesar_base_addresses_write_address(data(caesar_base_addresses_write_address(1)));
173    result.base_addresses(2).write_address := to_caesar_base_addresses_write_address(data(caesar_base_addresses_write_address(2)));
174
175    return result;
176  end function;
177
178  function to_caesar_reg_was_read(
179    data : caesar_reg_was_accessed_t
180  ) return caesar_reg_was_read_t is
181    variable result : caesar_reg_was_read_t := caesar_reg_was_read_init;
182  begin
183    result.base_addresses(0).read_address := data(caesar_base_addresses_read_address(array_index=>0));
184    result.base_addresses(1).read_address := data(caesar_base_addresses_read_address(array_index=>1));
185    result.base_addresses(2).read_address := data(caesar_base_addresses_read_address(array_index=>2));
186    result.base_addresses(0).write_address := data(caesar_base_addresses_write_address(array_index=>0));
187    result.base_addresses(1).write_address := data(caesar_base_addresses_write_address(array_index=>1));
188    result.base_addresses(2).write_address := data(caesar_base_addresses_write_address(array_index=>2));
189
190    return result;
191  end function;
192
193  function to_caesar_reg_was_written(
194    data : caesar_reg_was_accessed_t
195  ) return caesar_reg_was_written_t is
196    variable result : caesar_reg_was_written_t := caesar_reg_was_written_init;
197  begin
198    result.base_addresses(0).read_address := data(caesar_base_addresses_read_address(array_index=>0));
199    result.base_addresses(1).read_address := data(caesar_base_addresses_read_address(array_index=>1));
200    result.base_addresses(2).read_address := data(caesar_base_addresses_read_address(array_index=>2));
201    result.base_addresses(0).write_address := data(caesar_base_addresses_write_address(array_index=>0));
202    result.base_addresses(1).write_address := data(caesar_base_addresses_write_address(array_index=>1));
203    result.base_addresses(2).write_address := data(caesar_base_addresses_write_address(array_index=>2));
204
205    return result;
206  end function;
207
208end package body;

C++

The C++ interface header and implementation code below is produced by the generate() call in the Python example above. Click the button to expand and view each code block.

The class header is skipped here, since its inclusion would make this page very long. See C++ code generator for more details and an example of how the excluded file might look.

C++ interface header

Note how setters and getters for register and field values have a new argument for the array index.

Click to expand/collapse code.
Generated C++ interface class code.
  1// -----------------------------------------------------------------------------
  2// This file is automatically generated by hdl-registers version 7.0.2-dev.
  3// Code generator CppInterfaceGenerator version 1.0.0.
  4// Generated 2025-01-21 20:52 at commit 3c3e6c67d817.
  5// Register hash d398508c05f52d1800bf8d33954a99a6ebc864d8.
  6// -----------------------------------------------------------------------------
  7
  8#pragma once
  9
 10#include <sstream>
 11#include <cstdint>
 12#include <cstdlib>
 13
 14namespace fpga_regs
 15{
 16
 17  // Attributes for the 'address' field in the 'read_address' register within the 'base_addresses' register array.
 18  namespace caesar::base_addresses::read_address::address
 19  {
 20    static const auto width = 28;
 21    static const auto default_value = 0b0000000000000000000000000000;
 22  }
 23
 24  // Attributes for the 'address' field in the 'write_address' register within the 'base_addresses' register array.
 25  namespace caesar::base_addresses::write_address::address
 26  {
 27    static const auto width = 28;
 28    static const auto default_value = 0b0000000000000000000000000000;
 29  }
 30
 31  // Attributes for the "base_addresses" register array.
 32  namespace caesar::base_addresses
 33  {
 34    // Number of times the registers of the array are repeated.
 35    static const auto array_length = 3;
 36  };
 37
 38  class ICaesar
 39  {
 40  public:
 41    // Number of registers within this register list.
 42    static const size_t num_registers = 6uL;
 43
 44    virtual ~ICaesar() {}
 45
 46    // -------------------------------------------------------------------------
 47    // Methods for the 'read_address' register within the 'base_addresses' register array. Mode 'Read, Write'.
 48
 49    // Getter that will read the whole register's value over the register bus.
 50    virtual uint32_t get_base_addresses_read_address(
 51      size_t array_index
 52    ) const = 0;
 53
 54    // Setter that will write the whole register's value over the register bus.
 55    virtual void set_base_addresses_read_address(
 56      size_t array_index,
 57      uint32_t register_value
 58    ) const = 0;
 59
 60    // Getter for the 'address' field in the 'read_address' register within the 'base_addresses' register array,
 61    // which will read register value over the register bus.
 62    virtual uint32_t get_base_addresses_read_address_address(
 63      size_t array_index
 64    ) const = 0;
 65    // Getter for the 'address' field in the 'read_address' register within the 'base_addresses' register array,
 66    // given a register value.
 67    virtual uint32_t get_base_addresses_read_address_address_from_value(
 68      uint32_t register_value
 69    ) const = 0;
 70    // Setter for the 'address' field in the 'read_address' register within the 'base_addresses' register array,
 71    // which will set the field to the given value, and everything else to default.
 72    virtual void set_base_addresses_read_address_address(
 73      size_t array_index,
 74      uint32_t field_value
 75    ) const = 0;
 76    // Setter for the 'address' field in the 'read_address' register within the 'base_addresses' register array,
 77    // given a register value, which will return an updated value.
 78    virtual uint32_t set_base_addresses_read_address_address_from_value(
 79      uint32_t register_value,
 80      uint32_t field_value
 81    ) const = 0;
 82
 83    // -------------------------------------------------------------------------
 84    // Methods for the 'write_address' register within the 'base_addresses' register array. Mode 'Read, Write'.
 85
 86    // Getter that will read the whole register's value over the register bus.
 87    virtual uint32_t get_base_addresses_write_address(
 88      size_t array_index
 89    ) const = 0;
 90
 91    // Setter that will write the whole register's value over the register bus.
 92    virtual void set_base_addresses_write_address(
 93      size_t array_index,
 94      uint32_t register_value
 95    ) const = 0;
 96
 97    // Getter for the 'address' field in the 'write_address' register within the 'base_addresses' register array,
 98    // which will read register value over the register bus.
 99    virtual uint32_t get_base_addresses_write_address_address(
100      size_t array_index
101    ) const = 0;
102    // Getter for the 'address' field in the 'write_address' register within the 'base_addresses' register array,
103    // given a register value.
104    virtual uint32_t get_base_addresses_write_address_address_from_value(
105      uint32_t register_value
106    ) const = 0;
107    // Setter for the 'address' field in the 'write_address' register within the 'base_addresses' register array,
108    // which will set the field to the given value, and everything else to default.
109    virtual void set_base_addresses_write_address_address(
110      size_t array_index,
111      uint32_t field_value
112    ) const = 0;
113    // Setter for the 'address' field in the 'write_address' register within the 'base_addresses' register array,
114    // given a register value, which will return an updated value.
115    virtual uint32_t set_base_addresses_write_address_address_from_value(
116      uint32_t register_value,
117      uint32_t field_value
118    ) const = 0;
119
120  };
121
122} /* namespace fpga_regs */

C++ implementation

The C++ implementation code below is produced by the generate() call in the Python example above. Click the button to expand and view the code.

Note that there is an assertion in every setter and getter that the provided array index does not exceed the number of times the register array is repeated. This will catch calculation errors during testing and at run-time.

Click to expand/collapse code.
Generated C++ interface class code.
  1// -----------------------------------------------------------------------------
  2// This file is automatically generated by hdl-registers version 7.0.2-dev.
  3// Code generator CppInterfaceGenerator version 1.0.0.
  4// Generated 2025-01-21 20:52 at commit 3c3e6c67d817.
  5// Register hash d398508c05f52d1800bf8d33954a99a6ebc864d8.
  6// -----------------------------------------------------------------------------
  7
  8#pragma once
  9
 10#include <sstream>
 11#include <cstdint>
 12#include <cstdlib>
 13
 14namespace fpga_regs
 15{
 16
 17  // Attributes for the 'address' field in the 'read_address' register within the 'base_addresses' register array.
 18  namespace caesar::base_addresses::read_address::address
 19  {
 20    static const auto width = 28;
 21    static const auto default_value = 0b0000000000000000000000000000;
 22  }
 23
 24  // Attributes for the 'address' field in the 'write_address' register within the 'base_addresses' register array.
 25  namespace caesar::base_addresses::write_address::address
 26  {
 27    static const auto width = 28;
 28    static const auto default_value = 0b0000000000000000000000000000;
 29  }
 30
 31  // Attributes for the "base_addresses" register array.
 32  namespace caesar::base_addresses
 33  {
 34    // Number of times the registers of the array are repeated.
 35    static const auto array_length = 3;
 36  };
 37
 38  class ICaesar
 39  {
 40  public:
 41    // Number of registers within this register list.
 42    static const size_t num_registers = 6uL;
 43
 44    virtual ~ICaesar() {}
 45
 46    // -------------------------------------------------------------------------
 47    // Methods for the 'read_address' register within the 'base_addresses' register array. Mode 'Read, Write'.
 48
 49    // Getter that will read the whole register's value over the register bus.
 50    virtual uint32_t get_base_addresses_read_address(
 51      size_t array_index
 52    ) const = 0;
 53
 54    // Setter that will write the whole register's value over the register bus.
 55    virtual void set_base_addresses_read_address(
 56      size_t array_index,
 57      uint32_t register_value
 58    ) const = 0;
 59
 60    // Getter for the 'address' field in the 'read_address' register within the 'base_addresses' register array,
 61    // which will read register value over the register bus.
 62    virtual uint32_t get_base_addresses_read_address_address(
 63      size_t array_index
 64    ) const = 0;
 65    // Getter for the 'address' field in the 'read_address' register within the 'base_addresses' register array,
 66    // given a register value.
 67    virtual uint32_t get_base_addresses_read_address_address_from_value(
 68      uint32_t register_value
 69    ) const = 0;
 70    // Setter for the 'address' field in the 'read_address' register within the 'base_addresses' register array,
 71    // which will set the field to the given value, and everything else to default.
 72    virtual void set_base_addresses_read_address_address(
 73      size_t array_index,
 74      uint32_t field_value
 75    ) const = 0;
 76    // Setter for the 'address' field in the 'read_address' register within the 'base_addresses' register array,
 77    // given a register value, which will return an updated value.
 78    virtual uint32_t set_base_addresses_read_address_address_from_value(
 79      uint32_t register_value,
 80      uint32_t field_value
 81    ) const = 0;
 82
 83    // -------------------------------------------------------------------------
 84    // Methods for the 'write_address' register within the 'base_addresses' register array. Mode 'Read, Write'.
 85
 86    // Getter that will read the whole register's value over the register bus.
 87    virtual uint32_t get_base_addresses_write_address(
 88      size_t array_index
 89    ) const = 0;
 90
 91    // Setter that will write the whole register's value over the register bus.
 92    virtual void set_base_addresses_write_address(
 93      size_t array_index,
 94      uint32_t register_value
 95    ) const = 0;
 96
 97    // Getter for the 'address' field in the 'write_address' register within the 'base_addresses' register array,
 98    // which will read register value over the register bus.
 99    virtual uint32_t get_base_addresses_write_address_address(
100      size_t array_index
101    ) const = 0;
102    // Getter for the 'address' field in the 'write_address' register within the 'base_addresses' register array,
103    // given a register value.
104    virtual uint32_t get_base_addresses_write_address_address_from_value(
105      uint32_t register_value
106    ) const = 0;
107    // Setter for the 'address' field in the 'write_address' register within the 'base_addresses' register array,
108    // which will set the field to the given value, and everything else to default.
109    virtual void set_base_addresses_write_address_address(
110      size_t array_index,
111      uint32_t field_value
112    ) const = 0;
113    // Setter for the 'address' field in the 'write_address' register within the 'base_addresses' register array,
114    // given a register value, which will return an updated value.
115    virtual uint32_t set_base_addresses_write_address_address_from_value(
116      uint32_t register_value,
117      uint32_t field_value
118    ) const = 0;
119
120  };
121
122} /* namespace fpga_regs */

C header

The C code below is produced by the generate() call in the Python example above. The index and address of each register are given by a macro where the array index is supplied as an argument.

Click to expand/collapse code.
Generated C code.
 1// -----------------------------------------------------------------------------
 2// This file is automatically generated by hdl-registers version 7.0.2-dev.
 3// Code generator CHeaderGenerator version 1.0.0.
 4// Generated 2025-01-21 20:52 at commit 3c3e6c67d817.
 5// Register hash d398508c05f52d1800bf8d33954a99a6ebc864d8.
 6// -----------------------------------------------------------------------------
 7
 8#ifndef CAESAR_REGS_H
 9#define CAESAR_REGS_H
10
11
12// Number of registers within this register list.
13#define CAESAR_NUM_REGS (6u)
14
15// Type for the 'base_addresses' register array.
16typedef struct caesar_base_addresses_t
17{
18  // Mode 'Read, Write'.
19  uint32_t read_address;
20  // Mode 'Read, Write'.
21  uint32_t write_address;
22} caesar_base_addresses_t;
23
24// Type for this register list.
25typedef struct caesar_regs_t
26{
27  caesar_base_addresses_t base_addresses[3];
28} caesar_regs_t;
29
30// Address of the 'read_address' register within the 'base_addresses' register array (array_index < 3).
31// Mode 'Read, Write'.
32#define CAESAR_BASE_ADDRESSES_READ_ADDRESS_INDEX(array_index) (0u + (array_index) * 2u + 0u)
33#define CAESAR_BASE_ADDRESSES_READ_ADDRESS_ADDR(array_index) (4u * CAESAR_BASE_ADDRESSES_READ_ADDRESS_INDEX(array_index))
34// Attributes for the 'address' field in the 'read_address' register within the 'base_addresses' register array.
35#define CAESAR_BASE_ADDRESSES_READ_ADDRESS_ADDRESS_SHIFT (0u)
36#define CAESAR_BASE_ADDRESSES_READ_ADDRESS_ADDRESS_MASK (0b1111111111111111111111111111u << 0u)
37#define CAESAR_BASE_ADDRESSES_READ_ADDRESS_ADDRESS_MASK_INVERSE (~CAESAR_BASE_ADDRESSES_READ_ADDRESS_ADDRESS_MASK)
38
39// Address of the 'write_address' register within the 'base_addresses' register array (array_index < 3).
40// Mode 'Read, Write'.
41#define CAESAR_BASE_ADDRESSES_WRITE_ADDRESS_INDEX(array_index) (0u + (array_index) * 2u + 1u)
42#define CAESAR_BASE_ADDRESSES_WRITE_ADDRESS_ADDR(array_index) (4u * CAESAR_BASE_ADDRESSES_WRITE_ADDRESS_INDEX(array_index))
43// Attributes for the 'address' field in the 'write_address' register within the 'base_addresses' register array.
44#define CAESAR_BASE_ADDRESSES_WRITE_ADDRESS_ADDRESS_SHIFT (0u)
45#define CAESAR_BASE_ADDRESSES_WRITE_ADDRESS_ADDRESS_MASK (0b1111111111111111111111111111u << 0u)
46#define CAESAR_BASE_ADDRESSES_WRITE_ADDRESS_ADDRESS_MASK_INVERSE (~CAESAR_BASE_ADDRESSES_WRITE_ADDRESS_ADDRESS_MASK)
47
48#endif // CAESAR_REGS_H