Integer fields

Register fields can be of the type integer. Meaning, a numeric field, as opposed to a bit vector, that has a defined upper and lower range.

This page will show you how the set up integer fields in a register, 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 with three integer fields. See comments for rules about the different properties.

TOML that sets up a register with integer fields.
 1[config]
 2
 3mode = "r_w"
 4description = "Configuration register."
 5
 6# This will allocate an integer field named "burst_length_bytes" in the "config" register.
 7# The "type" property MUST be present and set to "integer".
 8burst_length_bytes.type = "integer"
 9
10# The "min_value" property is OPTIONAL for an integer field.
11# Will default to 0 if not specified.
12# The value specified MUST be an integer.
13burst_length_bytes.min_value = 1
14
15# The "max_value" property MUST be present for an integer field.
16# The value specified MUST be an integer, and greater than or equal to the
17# "min_value" parameter value.
18burst_length_bytes.max_value = 256
19
20# The "description" property is OPTIONAL for an integer field.
21# Will default to "" if not specified.
22# The value specified MUST be a string.
23burst_length_bytes.description = "The number of bytes to request."
24
25# The "default_value" property is OPTIONAL for a integer field.
26# Will default to the "min_value" parameter value if not specified.
27# The value specified MUST be an integer within the specified min/max range.
28burst_length_bytes.default_value = 64
29
30
31increment.type = "integer"
32increment.min_value = -4
33increment.max_value = 3
34increment.description = "Offset that will be added to data."
35increment.default_value = 0
36
37
38retry_count.type = "integer"
39retry_count.max_value = 5
40retry_count.description = "Number of retry attempts before giving up."

Note that the second field has a negative range, which is fully supported. Note also that the third field does not any lower bound specified, meaning it will default to zero. It furthermore does not have any default value, meaning it will automatically default to the lower bound, i.e. zero.

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 with integer fields.
 1import sys
 2from pathlib import Path
 3
 4from hdl_registers.generator.c.header import CHeaderGenerator
 5from hdl_registers.generator.cpp.implementation import CppImplementationGenerator
 6from hdl_registers.generator.cpp.interface import CppInterfaceGenerator
 7from hdl_registers.generator.html.page import HtmlPageGenerator
 8from hdl_registers.generator.vhdl.record_package import VhdlRecordPackageGenerator
 9from hdl_registers.generator.vhdl.register_package import VhdlRegisterPackageGenerator
10from hdl_registers.parser.toml import from_toml
11from hdl_registers.register_list import RegisterList
12from hdl_registers.register_modes import REGISTER_MODES
13
14THIS_DIR = Path(__file__).parent
15
16
17def parse_toml() -> RegisterList:
18    """
19    Create the register list by parsing a TOML data file.
20    """
21    return from_toml(name="caesar", toml_file=THIS_DIR.parent / "toml" / "field_integer.toml")
22
23
24def create_from_api() -> RegisterList:
25    """
26    Alternative method: Create the register list by using the Python API.
27    """
28    register_list = RegisterList(name="caesar")
29
30    register = register_list.append_register(
31        name="config", mode=REGISTER_MODES["r_w"], description="Configuration register."
32    )
33
34    register.append_integer(
35        name="burst_length_bytes",
36        description="The number of bytes to request.",
37        min_value=1,
38        max_value=256,
39        default_value=64,
40    )
41
42    register.append_integer(
43        name="increment",
44        description="Offset that will be added to data.",
45        min_value=-4,
46        max_value=3,
47        default_value=0,
48    )
49
50    register.append_integer(
51        name="retry_count",
52        description="Number of retry attempts before giving up.",
53        min_value=0,
54        max_value=5,
55        default_value=0,
56    )
57
58    return register_list
59
60
61def generate(register_list: RegisterList, output_folder: Path) -> None:
62    """
63    Generate the artifacts that we are interested in.
64    """
65    CHeaderGenerator(register_list=register_list, output_folder=output_folder).create()
66
67    CppImplementationGenerator(register_list=register_list, output_folder=output_folder).create()
68    CppInterfaceGenerator(register_list=register_list, output_folder=output_folder).create()
69
70    HtmlPageGenerator(register_list=register_list, output_folder=output_folder).create()
71
72    VhdlRegisterPackageGenerator(register_list=register_list, output_folder=output_folder).create()
73    VhdlRecordPackageGenerator(register_list=register_list, output_folder=output_folder).create()
74
75
76def main(output_folder: Path) -> None:
77    generate(register_list=parse_toml(), output_folder=output_folder / "toml")
78    generate(register_list=create_from_api(), output_folder=output_folder / "api")
79
80
81if __name__ == "__main__":
82    main(output_folder=Path(sys.argv[1]))

See Register.append_integer() for more Python API details.

Generated code

See below for a description of the code that can be generated when using integer fields.

HTML page

See HTML file below for the human-readable documentation that is produced by the generate() call in the Python example above. Each integer field is documented with its valid range.

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

Some interesting things to notice:

  1. There is only one register, at index 0.

  2. VHDL supports integer types natively. For each field there is a sub-type that is a properly ranged integer.

  3. For each integer field, there are conversion functions for

    1. Converting from the integer type to std_logic_vector.

    2. Slicing a register value at the correct range and converting from std_logic_vector to integer.

Click to expand/collapse code.
Generated VHDL register package.
  1-- -----------------------------------------------------------------------------
  2-- This file is automatically generated by hdl-registers version 7.0.4-dev.
  3-- Code generator VhdlRegisterPackageGenerator version 2.0.0.
  4-- Generated 2025-02-15 20:51 at commit 150d1a2bbe0a.
  5-- Register hash 805a50de03b71b95d3523176ad9155b5fe7be903.
  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 0;
 22
 23  -- ---------------------------------------------------------------------------
 24  -- The number of bits needed to address all 1 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 := 3;
 28
 29  -- Register indexes, within the list of registers.
 30  constant caesar_config : natural := 0;
 31
 32  -- Declare 'register_map' and 'regs_init' constants here but define them in
 33  -- the package body (deferred constants).
 34  -- So that functions have been elaborated when they are called.
 35  -- Needed for ModelSim compilation to pass.
 36
 37  -- To be used as the 'registers' generic of 'axi_lite_register_file.vhd'.
 38  constant caesar_register_map : register_definition_vec_t(caesar_register_range);
 39
 40  -- To be used for the 'regs_up' and 'regs_down' ports of 'axi_lite_register_file.vhd'.
 41  subtype caesar_regs_t is register_vec_t(caesar_register_range);
 42  -- To be used as the 'default_values' generic of 'axi_lite_register_file.vhd'.
 43  constant caesar_regs_init : caesar_regs_t;
 44
 45  -- To be used for the 'reg_was_read' and 'reg_was_written' ports of 'axi_lite_register_file.vhd'.
 46  subtype caesar_reg_was_accessed_t is std_ulogic_vector(caesar_register_range);
 47
 48  -- -----------------------------------------------------------------------------
 49  -- Fields in the 'config' register.
 50  -- Range of the 'burst_length_bytes' field.
 51  subtype caesar_config_burst_length_bytes is natural range 8 downto 0;
 52  -- Width of the 'burst_length_bytes' field.
 53  constant caesar_config_burst_length_bytes_width : positive := 9;
 54  -- Type for the 'burst_length_bytes' field.
 55  subtype caesar_config_burst_length_bytes_t is integer range 1 to 256;
 56  -- Default value of the 'burst_length_bytes' field.
 57  constant caesar_config_burst_length_bytes_init : caesar_config_burst_length_bytes_t := 64;
 58  -- Type for the 'burst_length_bytes' field as an SLV.
 59  subtype caesar_config_burst_length_bytes_slv_t is std_ulogic_vector(8 downto 0);
 60  -- Cast a 'burst_length_bytes' field value to SLV.
 61  function to_caesar_config_burst_length_bytes_slv(data : caesar_config_burst_length_bytes_t) return caesar_config_burst_length_bytes_slv_t;
 62  -- Get a 'burst_length_bytes' field value from a register value.
 63  function to_caesar_config_burst_length_bytes(data : register_t) return caesar_config_burst_length_bytes_t;
 64
 65  -- Range of the 'increment' field.
 66  subtype caesar_config_increment is natural range 11 downto 9;
 67  -- Width of the 'increment' field.
 68  constant caesar_config_increment_width : positive := 3;
 69  -- Type for the 'increment' field.
 70  subtype caesar_config_increment_t is integer range -4 to 3;
 71  -- Default value of the 'increment' field.
 72  constant caesar_config_increment_init : caesar_config_increment_t := 0;
 73  -- Type for the 'increment' field as an SLV.
 74  subtype caesar_config_increment_slv_t is std_ulogic_vector(2 downto 0);
 75  -- Cast a 'increment' field value to SLV.
 76  function to_caesar_config_increment_slv(data : caesar_config_increment_t) return caesar_config_increment_slv_t;
 77  -- Get a 'increment' field value from a register value.
 78  function to_caesar_config_increment(data : register_t) return caesar_config_increment_t;
 79
 80  -- Range of the 'retry_count' field.
 81  subtype caesar_config_retry_count is natural range 14 downto 12;
 82  -- Width of the 'retry_count' field.
 83  constant caesar_config_retry_count_width : positive := 3;
 84  -- Type for the 'retry_count' field.
 85  subtype caesar_config_retry_count_t is integer range 0 to 5;
 86  -- Default value of the 'retry_count' field.
 87  constant caesar_config_retry_count_init : caesar_config_retry_count_t := 0;
 88  -- Type for the 'retry_count' field as an SLV.
 89  subtype caesar_config_retry_count_slv_t is std_ulogic_vector(2 downto 0);
 90  -- Cast a 'retry_count' field value to SLV.
 91  function to_caesar_config_retry_count_slv(data : caesar_config_retry_count_t) return caesar_config_retry_count_slv_t;
 92  -- Get a 'retry_count' field value from a register value.
 93  function to_caesar_config_retry_count(data : register_t) return caesar_config_retry_count_t;
 94
 95end package;
 96
 97package body caesar_regs_pkg is
 98
 99  constant caesar_register_map : register_definition_vec_t(caesar_register_range) := (
100    0 => (index => caesar_config, mode => r_w, utilized_width => 15)
101  );
102
103  constant caesar_regs_init : caesar_regs_t := (
104    0 => "00000000000000000000000001000000"
105  );
106
107  -- Cast a 'burst_length_bytes' field value to SLV.
108  function to_caesar_config_burst_length_bytes_slv(data : caesar_config_burst_length_bytes_t) return caesar_config_burst_length_bytes_slv_t is
109    constant result : caesar_config_burst_length_bytes_slv_t := std_ulogic_vector(to_unsigned(data, caesar_config_burst_length_bytes_width));
110  begin
111    return result;
112  end function;
113
114  -- Get a 'burst_length_bytes' field value from a register value.
115  function to_caesar_config_burst_length_bytes(data : register_t) return caesar_config_burst_length_bytes_t is
116    constant result : integer := to_integer(unsigned(data(caesar_config_burst_length_bytes)));
117  begin
118    return result;
119  end function;
120
121  -- Cast a 'increment' field value to SLV.
122  function to_caesar_config_increment_slv(data : caesar_config_increment_t) return caesar_config_increment_slv_t is
123    constant result : caesar_config_increment_slv_t := std_ulogic_vector(to_signed(data, caesar_config_increment_width));
124  begin
125    return result;
126  end function;
127
128  -- Get a 'increment' field value from a register value.
129  function to_caesar_config_increment(data : register_t) return caesar_config_increment_t is
130    constant result : integer := to_integer(signed(data(caesar_config_increment)));
131  begin
132    return result;
133  end function;
134
135  -- Cast a 'retry_count' field value to SLV.
136  function to_caesar_config_retry_count_slv(data : caesar_config_retry_count_t) return caesar_config_retry_count_slv_t is
137    constant result : caesar_config_retry_count_slv_t := std_ulogic_vector(to_unsigned(data, caesar_config_retry_count_width));
138  begin
139    return result;
140  end function;
141
142  -- Get a 'retry_count' field value from a register value.
143  function to_caesar_config_retry_count(data : register_t) return caesar_config_retry_count_t is
144    constant result : integer := to_integer(unsigned(data(caesar_config_retry_count)));
145  begin
146    return result;
147  end function;
148
149end package body;

Record package

The caesar_regs_down_t type is a record with a member config, the only register in this example. The type of the config member is another record with the three integers set up in our example: burst_length_bytes, increment and retry_count. These are of integer types defined in the base register package above.

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

result_data <= input_data + regs_down.config.increment;
Click to expand/collapse code.
Generated VHDL record package.
  1-- -----------------------------------------------------------------------------
  2-- This file is automatically generated by hdl-registers version 7.0.4-dev.
  3-- Code generator VhdlRecordPackageGenerator version 1.0.0.
  4-- Generated 2025-02-15 20:51 at commit 150d1a2bbe0a.
  5-- Register hash 805a50de03b71b95d3523176ad9155b5fe7be903.
  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 'config' register as a record.
 24  type caesar_config_t is record
 25    burst_length_bytes : caesar_config_burst_length_bytes_t;
 26    increment : caesar_config_increment_t;
 27    retry_count : caesar_config_retry_count_t;
 28  end record;
 29  -- Default value for the 'config' register as a record.
 30  constant caesar_config_init : caesar_config_t := (
 31    burst_length_bytes => caesar_config_burst_length_bytes_init,
 32    increment => caesar_config_increment_init,
 33    retry_count => caesar_config_retry_count_init
 34  );
 35  -- Convert a record of the 'config' register to SLV.
 36  function to_slv(data : caesar_config_t) return register_t;
 37  -- Convert an SLV register value to the record for the 'config' register.
 38  function to_caesar_config(data : register_t) return caesar_config_t;
 39
 40  -- -----------------------------------------------------------------------------
 41  -- Below is a record with correctly typed and ranged members for all registers, register arrays
 42  -- and fields that are in the 'down' direction.
 43  -- Record with everything in the 'down' direction.
 44  type caesar_regs_down_t is record
 45    config : caesar_config_t;
 46  end record;
 47  -- Default value of the above record.
 48  constant caesar_regs_down_init : caesar_regs_down_t := (
 49    config => caesar_config_init
 50  );
 51  -- Convert SLV register list to record with everything in the 'down' direction.
 52  function to_caesar_regs_down(data : caesar_regs_t) return caesar_regs_down_t;
 53
 54  -- ---------------------------------------------------------------------------
 55  -- Below is a record with a status bit for each readable register in the register list.
 56  -- It can be used for the 'reg_was_read' port of a register file wrapper.
 57  -- Combined status mask record for all readable register.
 58  type caesar_reg_was_read_t is record
 59    config : std_ulogic;
 60  end record;
 61  -- Default value for the above record.
 62  constant caesar_reg_was_read_init : caesar_reg_was_read_t := (
 63    others => '0'
 64  );
 65  -- Convert an SLV 'reg_was_read' from generic register file to the record above.
 66  function to_caesar_reg_was_read(
 67    data : caesar_reg_was_accessed_t
 68  ) return caesar_reg_was_read_t;
 69
 70  -- ---------------------------------------------------------------------------
 71  -- Below is a record with a status bit for each writeable register in the register list.
 72  -- It can be used for the 'reg_was_written' port of a register file wrapper.
 73  -- Combined status mask record for all writeable register.
 74  type caesar_reg_was_written_t is record
 75    config : std_ulogic;
 76  end record;
 77  -- Default value for the above record.
 78  constant caesar_reg_was_written_init : caesar_reg_was_written_t := (
 79    others => '0'
 80  );
 81  -- Convert an SLV 'reg_was_written' from generic register file to the record above.
 82  function to_caesar_reg_was_written(
 83    data : caesar_reg_was_accessed_t
 84  ) return caesar_reg_was_written_t;
 85
 86end package;
 87
 88package body caesar_register_record_pkg is
 89
 90  function to_slv(data : caesar_config_t) return register_t is
 91    variable result : register_t := (others => '-');
 92  begin
 93    result(caesar_config_burst_length_bytes) := to_caesar_config_burst_length_bytes_slv(data.burst_length_bytes);
 94    result(caesar_config_increment) := to_caesar_config_increment_slv(data.increment);
 95    result(caesar_config_retry_count) := to_caesar_config_retry_count_slv(data.retry_count);
 96
 97    return result;
 98  end function;
 99
100  function to_caesar_config(data : register_t) return caesar_config_t is
101    variable result : caesar_config_t := caesar_config_init;
102  begin
103    result.burst_length_bytes := to_caesar_config_burst_length_bytes(data);
104    result.increment := to_caesar_config_increment(data);
105    result.retry_count := to_caesar_config_retry_count(data);
106
107    return result;
108  end function;
109
110  function to_caesar_regs_down(data : caesar_regs_t) return caesar_regs_down_t is
111    variable result : caesar_regs_down_t := caesar_regs_down_init;
112  begin
113    result.config := to_caesar_config(data(caesar_config));
114
115    return result;
116  end function;
117
118  function to_caesar_reg_was_read(
119    data : caesar_reg_was_accessed_t
120  ) return caesar_reg_was_read_t is
121    variable result : caesar_reg_was_read_t := caesar_reg_was_read_init;
122  begin
123    result.config := data(caesar_config);
124
125    return result;
126  end function;
127
128  function to_caesar_reg_was_written(
129    data : caesar_reg_was_accessed_t
130  ) return caesar_reg_was_written_t is
131    variable result : caesar_reg_was_written_t := caesar_reg_was_written_init;
132  begin
133    result.config := data(caesar_config);
134
135    return result;
136  end function;
137
138end 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 that the setters and getters for each field value use integer types as argument or return value. The signed field uses int32_t while the unsigned fields use uint32_t.

Click to expand/collapse code.
Generated C++ class interface code.
  1// -----------------------------------------------------------------------------
  2// This file is automatically generated by hdl-registers version 7.0.4-dev.
  3// Code generator CppInterfaceGenerator version 1.0.0.
  4// Generated 2025-02-15 20:51 at commit 150d1a2bbe0a.
  5// Register hash 805a50de03b71b95d3523176ad9155b5fe7be903.
  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 'burst_length_bytes' field in the 'config' register.
 18  namespace caesar::config::burst_length_bytes
 19  {
 20    static const auto width = 9;
 21    static const auto default_value = 64;
 22  }
 23  // Attributes for the 'increment' field in the 'config' register.
 24  namespace caesar::config::increment
 25  {
 26    static const auto width = 3;
 27    static const auto default_value = 0;
 28  }
 29  // Attributes for the 'retry_count' field in the 'config' register.
 30  namespace caesar::config::retry_count
 31  {
 32    static const auto width = 3;
 33    static const auto default_value = 0;
 34  }
 35
 36  class ICaesar
 37  {
 38  public:
 39    // Number of registers within this register list.
 40    static const size_t num_registers = 1uL;
 41
 42    virtual ~ICaesar() {}
 43
 44    // -------------------------------------------------------------------------
 45    // Methods for the 'config' register. Mode 'Read, Write'.
 46
 47    // Getter that will read the whole register's value over the register bus.
 48    virtual uint32_t get_config() const = 0;
 49
 50    // Setter that will write the whole register's value over the register bus.
 51    virtual void set_config(
 52      uint32_t register_value
 53    ) const = 0;
 54
 55    // Getter for the 'burst_length_bytes' field in the 'config' register,
 56    // which will read register value over the register bus.
 57    virtual uint32_t get_config_burst_length_bytes() const = 0;
 58    // Getter for the 'burst_length_bytes' field in the 'config' register,
 59    // given a register value.
 60    virtual uint32_t get_config_burst_length_bytes_from_value(
 61      uint32_t register_value
 62    ) const = 0;
 63    // Setter for the 'burst_length_bytes' field in the 'config' register,
 64    // which will read-modify-write over the register bus.
 65    virtual void set_config_burst_length_bytes(
 66      uint32_t field_value
 67    ) const = 0;
 68    // Setter for the 'burst_length_bytes' field in the 'config' register,
 69    // given a register value, which will return an updated value.
 70    virtual uint32_t set_config_burst_length_bytes_from_value(
 71      uint32_t register_value,
 72      uint32_t field_value
 73    ) const = 0;
 74
 75    // Getter for the 'increment' field in the 'config' register,
 76    // which will read register value over the register bus.
 77    virtual int32_t get_config_increment() const = 0;
 78    // Getter for the 'increment' field in the 'config' register,
 79    // given a register value.
 80    virtual int32_t get_config_increment_from_value(
 81      uint32_t register_value
 82    ) const = 0;
 83    // Setter for the 'increment' field in the 'config' register,
 84    // which will read-modify-write over the register bus.
 85    virtual void set_config_increment(
 86      int32_t field_value
 87    ) const = 0;
 88    // Setter for the 'increment' field in the 'config' register,
 89    // given a register value, which will return an updated value.
 90    virtual uint32_t set_config_increment_from_value(
 91      uint32_t register_value,
 92      int32_t field_value
 93    ) const = 0;
 94
 95    // Getter for the 'retry_count' field in the 'config' register,
 96    // which will read register value over the register bus.
 97    virtual uint32_t get_config_retry_count() const = 0;
 98    // Getter for the 'retry_count' field in the 'config' register,
 99    // given a register value.
100    virtual uint32_t get_config_retry_count_from_value(
101      uint32_t register_value
102    ) const = 0;
103    // Setter for the 'retry_count' field in the 'config' register,
104    // which will read-modify-write over the register bus.
105    virtual void set_config_retry_count(
106      uint32_t field_value
107    ) const = 0;
108    // Setter for the 'retry_count' field in the 'config' register,
109    // given a register value, which will return an updated value.
110    virtual uint32_t set_config_retry_count_from_value(
111      uint32_t register_value,
112      uint32_t field_value
113    ) const = 0;
114
115  };
116
117} /* namespace fpga_regs */

C++ implementation

Note that each setter and getter perform assertions that the supplied argument is withing the legal range of the field. This will catch calculation errors during testing and at run-time.

Click to expand/collapse code.
Generated C++ class implementation code.
  1// -----------------------------------------------------------------------------
  2// This file is automatically generated by hdl-registers version 7.0.4-dev.
  3// Code generator CppImplementationGenerator version 2.0.0.
  4// Generated 2025-02-15 20:51 at commit 150d1a2bbe0a.
  5// Register hash 805a50de03b71b95d3523176ad9155b5fe7be903.
  6// -----------------------------------------------------------------------------
  7
  8#include "include/caesar.h"
  9
 10namespace fpga_regs
 11{
 12
 13#ifdef NO_REGISTER_SETTER_ASSERT
 14
 15#define _SETTER_ASSERT_TRUE(expression, message) ((void)0)
 16
 17#else // Not NO_REGISTER_SETTER_ASSERT.
 18
 19// This macro is called by the register code to check for runtime errors.
 20#define _SETTER_ASSERT_TRUE(expression, message)                                 \
 21  {                                                                              \
 22    if (!static_cast<bool>(expression)) {                                        \
 23      std::ostringstream diagnostics;                                            \
 24      diagnostics << "Tried to set value out of range in " << __FILE__ << ":"    \
 25                  << __LINE__ << ", message: " << message << ".";                \
 26      std::string diagnostic_message = diagnostics.str();                        \
 27      m_assertion_handler(&diagnostic_message);                                  \
 28    }                                                                            \
 29  }
 30
 31#endif // NO_REGISTER_SETTER_ASSERT.
 32
 33#ifdef NO_REGISTER_GETTER_ASSERT
 34
 35#define _GETTER_ASSERT_TRUE(expression, message) ((void)0)
 36
 37#else // Not NO_REGISTER_GETTER_ASSERT.
 38
 39// This macro is called by the register code to check for runtime errors.
 40#define _GETTER_ASSERT_TRUE(expression, message)                                 \
 41  {                                                                              \
 42    if (!static_cast<bool>(expression)) {                                        \
 43      std::ostringstream diagnostics;                                            \
 44      diagnostics << "Got read value out of range in " << __FILE__ << ":"        \
 45                  << __LINE__ << ", message: " << message << ".";                \
 46      std::string diagnostic_message = diagnostics.str();                        \
 47      m_assertion_handler(&diagnostic_message);                                  \
 48    }                                                                            \
 49  }
 50
 51#endif // NO_REGISTER_GETTER_ASSERT.
 52
 53#ifdef NO_REGISTER_ARRAY_INDEX_ASSERT
 54
 55#define _ARRAY_INDEX_ASSERT_TRUE(expression, message) ((void)0)
 56
 57#else // Not NO_REGISTER_ARRAY_INDEX_ASSERT.
 58
 59// This macro is called by the register code to check for runtime errors.
 60#define _ARRAY_INDEX_ASSERT_TRUE(expression, message)                            \
 61  {                                                                              \
 62    if (!static_cast<bool>(expression)) {                                        \
 63      std::ostringstream diagnostics;                                            \
 64      diagnostics << "Provided array index out of range in " << __FILE__ << ":"  \
 65                  << __LINE__ << ", message: " << message << ".";                \
 66      std::string diagnostic_message = diagnostics.str();                        \
 67      m_assertion_handler(&diagnostic_message);                                  \
 68    }                                                                            \
 69  }
 70
 71#endif // NO_REGISTER_ARRAY_INDEX_ASSERT.
 72
 73  Caesar::Caesar(uintptr_t base_address, bool (*assertion_handler) (const std::string*))
 74      : m_registers(reinterpret_cast<volatile uint32_t *>(base_address)),
 75        m_assertion_handler(assertion_handler)
 76  {
 77    // Empty
 78  }
 79
 80  // ---------------------------------------------------------------------------
 81  // Methods for the 'config' register.
 82  // See interface header for documentation.
 83
 84  uint32_t Caesar::get_config() const
 85  {
 86    const size_t index = 0;
 87    const uint32_t result = m_registers[index];
 88
 89    return result;
 90  }
 91
 92  uint32_t Caesar::get_config_burst_length_bytes() const
 93  {
 94    const uint32_t register_value = get_config();
 95    const uint32_t field_value = get_config_burst_length_bytes_from_value(register_value);
 96
 97    return field_value;
 98  }
 99
100  uint32_t Caesar::get_config_burst_length_bytes_from_value(
101    uint32_t register_value
102  ) const
103  {
104    const uint32_t shift = 0uL;
105    const uint32_t mask_at_base = 0b111111111uL;
106    const uint32_t mask_shifted = mask_at_base << shift;
107
108    const uint32_t result_masked = register_value & mask_shifted;
109    const uint32_t result_shifted = result_masked >> shift;
110
111    uint32_t field_value;
112
113    // No casting needed.
114    field_value = result_shifted;
115
116    // Check that field value is within the legal range.
117    _GETTER_ASSERT_TRUE(
118      field_value >= 1,
119      "'burst_length_bytes' value too small, got '" << field_value << "'"
120    );
121    _GETTER_ASSERT_TRUE(
122      field_value <= 256,
123      "'burst_length_bytes' value too large, got '" << field_value << "'"
124    );
125
126    return field_value;
127  }
128
129  int32_t Caesar::get_config_increment() const
130  {
131    const uint32_t register_value = get_config();
132    const int32_t field_value = get_config_increment_from_value(register_value);
133
134    return field_value;
135  }
136
137  int32_t Caesar::get_config_increment_from_value(
138    uint32_t register_value
139  ) const
140  {
141    const uint32_t shift = 9uL;
142    const uint32_t mask_at_base = 0b111uL;
143    const uint32_t mask_shifted = mask_at_base << shift;
144
145    const uint32_t result_masked = register_value & mask_shifted;
146    const uint32_t result_shifted = result_masked >> shift;
147
148    int32_t field_value;
149
150    const int32_t sign_bit_mask = 1 << 2;
151
152    if (result_shifted & sign_bit_mask)
153    {
154      // Value is to be interpreted as negative.
155      // Sign extend it from the width of the field to the width of the return type.
156      field_value = result_shifted - 2 * sign_bit_mask;
157    }
158    else
159    {
160      // Value is positive.
161      field_value = result_shifted;
162    }
163
164    // Check that field value is within the legal range.
165    _GETTER_ASSERT_TRUE(
166      field_value >= -4,
167      "'increment' value too small, got '" << field_value << "'"
168    );
169    _GETTER_ASSERT_TRUE(
170      field_value <= 3,
171      "'increment' value too large, got '" << field_value << "'"
172    );
173
174    return field_value;
175  }
176
177  uint32_t Caesar::get_config_retry_count() const
178  {
179    const uint32_t register_value = get_config();
180    const uint32_t field_value = get_config_retry_count_from_value(register_value);
181
182    return field_value;
183  }
184
185  uint32_t Caesar::get_config_retry_count_from_value(
186    uint32_t register_value
187  ) const
188  {
189    const uint32_t shift = 12uL;
190    const uint32_t mask_at_base = 0b111uL;
191    const uint32_t mask_shifted = mask_at_base << shift;
192
193    const uint32_t result_masked = register_value & mask_shifted;
194    const uint32_t result_shifted = result_masked >> shift;
195
196    uint32_t field_value;
197
198    // No casting needed.
199    field_value = result_shifted;
200
201    // Check that field value is within the legal range.
202    _GETTER_ASSERT_TRUE(
203      field_value >= 0,
204      "'retry_count' value too small, got '" << field_value << "'"
205    );
206    _GETTER_ASSERT_TRUE(
207      field_value <= 5,
208      "'retry_count' value too large, got '" << field_value << "'"
209    );
210
211    return field_value;
212  }
213
214  void Caesar::set_config(
215    uint32_t register_value
216  ) const
217  {
218    const size_t index = 0;
219    m_registers[index] = register_value;
220  }
221
222  void Caesar::set_config_burst_length_bytes(
223    uint32_t field_value
224  ) const
225  {
226    // Get the current value of other fields by reading register on the bus.
227    const uint32_t current_register_value = get_config();
228    const uint32_t result_register_value = set_config_burst_length_bytes_from_value(current_register_value, field_value);
229    set_config(result_register_value);
230  }
231
232  uint32_t Caesar::set_config_burst_length_bytes_from_value(
233    uint32_t register_value,
234    uint32_t field_value
235  ) const  {
236    const uint32_t shift = 0uL;
237    const uint32_t mask_at_base = 0b111111111uL;
238    const uint32_t mask_shifted = mask_at_base << shift;
239
240    // Check that field value is within the legal range.
241    _SETTER_ASSERT_TRUE(
242      field_value >= 1,
243      "'burst_length_bytes' value too small, got '" << field_value << "'"
244    );
245    _SETTER_ASSERT_TRUE(
246      field_value <= 256,
247      "'burst_length_bytes' value too large, got '" << field_value << "'"
248    );
249
250    const uint32_t field_value_masked = field_value & mask_at_base;
251    const uint32_t field_value_masked_and_shifted = field_value_masked << shift;
252
253    const uint32_t mask_shifted_inverse = ~mask_shifted;
254    const uint32_t register_value_masked = register_value & mask_shifted_inverse;
255
256    const uint32_t result_register_value = register_value_masked | field_value_masked_and_shifted;
257
258    return result_register_value;
259  }
260
261  void Caesar::set_config_increment(
262    int32_t field_value
263  ) const
264  {
265    // Get the current value of other fields by reading register on the bus.
266    const uint32_t current_register_value = get_config();
267    const uint32_t result_register_value = set_config_increment_from_value(current_register_value, field_value);
268    set_config(result_register_value);
269  }
270
271  uint32_t Caesar::set_config_increment_from_value(
272    uint32_t register_value,
273    int32_t field_value
274  ) const  {
275    const uint32_t shift = 9uL;
276    const uint32_t mask_at_base = 0b111uL;
277    const uint32_t mask_shifted = mask_at_base << shift;
278
279    // Check that field value is within the legal range.
280    _SETTER_ASSERT_TRUE(
281      field_value >= -4,
282      "'increment' value too small, got '" << field_value << "'"
283    );
284    _SETTER_ASSERT_TRUE(
285      field_value <= 3,
286      "'increment' value too large, got '" << field_value << "'"
287    );
288
289    const uint32_t field_value_masked = field_value & mask_at_base;
290    const uint32_t field_value_masked_and_shifted = field_value_masked << shift;
291
292    const uint32_t mask_shifted_inverse = ~mask_shifted;
293    const uint32_t register_value_masked = register_value & mask_shifted_inverse;
294
295    const uint32_t result_register_value = register_value_masked | field_value_masked_and_shifted;
296
297    return result_register_value;
298  }
299
300  void Caesar::set_config_retry_count(
301    uint32_t field_value
302  ) const
303  {
304    // Get the current value of other fields by reading register on the bus.
305    const uint32_t current_register_value = get_config();
306    const uint32_t result_register_value = set_config_retry_count_from_value(current_register_value, field_value);
307    set_config(result_register_value);
308  }
309
310  uint32_t Caesar::set_config_retry_count_from_value(
311    uint32_t register_value,
312    uint32_t field_value
313  ) const  {
314    const uint32_t shift = 12uL;
315    const uint32_t mask_at_base = 0b111uL;
316    const uint32_t mask_shifted = mask_at_base << shift;
317
318    // Check that field value is within the legal range.
319    _SETTER_ASSERT_TRUE(
320      field_value >= 0,
321      "'retry_count' value too small, got '" << field_value << "'"
322    );
323    _SETTER_ASSERT_TRUE(
324      field_value <= 5,
325      "'retry_count' value too large, got '" << field_value << "'"
326    );
327
328    const uint32_t field_value_masked = field_value & mask_at_base;
329    const uint32_t field_value_masked_and_shifted = field_value_masked << shift;
330
331    const uint32_t mask_shifted_inverse = ~mask_shifted;
332    const uint32_t register_value_masked = register_value & mask_shifted_inverse;
333
334    const uint32_t result_register_value = register_value_masked | field_value_masked_and_shifted;
335
336    return result_register_value;
337  }
338
339} /* namespace fpga_regs */

C header

The C code below is produced by the generate() call in the Python example above. The range and mask of the each field are available as constants.

Click to expand/collapse code.
Generated C code.
 1// -----------------------------------------------------------------------------
 2// This file is automatically generated by hdl-registers version 7.0.4-dev.
 3// Code generator CHeaderGenerator version 1.0.0.
 4// Generated 2025-02-15 20:51 at commit 150d1a2bbe0a.
 5// Register hash 805a50de03b71b95d3523176ad9155b5fe7be903.
 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 (1u)
14
15// Type for this register list.
16typedef struct caesar_regs_t
17{
18  // Mode "Read, Write".
19  uint32_t config;
20} caesar_regs_t;
21
22// Address of the 'config' register.
23// Mode 'Read, Write'.
24#define CAESAR_CONFIG_INDEX (0u)
25#define CAESAR_CONFIG_ADDR (4u * CAESAR_CONFIG_INDEX)
26// Attributes for the 'burst_length_bytes' field in the 'config' register.
27#define CAESAR_CONFIG_BURST_LENGTH_BYTES_SHIFT (0u)
28#define CAESAR_CONFIG_BURST_LENGTH_BYTES_MASK (0b111111111u << 0u)
29#define CAESAR_CONFIG_BURST_LENGTH_BYTES_MASK_INVERSE (~CAESAR_CONFIG_BURST_LENGTH_BYTES_MASK)
30// Attributes for the 'increment' field in the 'config' register.
31#define CAESAR_CONFIG_INCREMENT_SHIFT (9u)
32#define CAESAR_CONFIG_INCREMENT_MASK (0b111u << 9u)
33#define CAESAR_CONFIG_INCREMENT_MASK_INVERSE (~CAESAR_CONFIG_INCREMENT_MASK)
34// Attributes for the 'retry_count' field in the 'config' register.
35#define CAESAR_CONFIG_RETRY_COUNT_SHIFT (12u)
36#define CAESAR_CONFIG_RETRY_COUNT_MASK (0b111u << 12u)
37#define CAESAR_CONFIG_RETRY_COUNT_MASK_INVERSE (~CAESAR_CONFIG_RETRY_COUNT_MASK)
38
39#endif // CAESAR_REGS_H