Enumeration fields

Register fields can be of the type enumeration. Meaning, a field that can only take on a limited, pre-defined, and named, set of values. This is a very common and highly useful programming concept. See Wikipedia if you are unfamiliar with this: https://en.wikipedia.org/wiki/Enumerated_type

This page will show you how the set up enumeration 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 two enumeration fields. See comments for rules about the different properties.

TOML that sets up a register with enumeration fields.
 1[conf]
 2
 3mode = "r_w"
 4description = "Configuration register."
 5
 6# This will allocate an enumeration field named "severity_level" in the "conf" register.
 7# The "type" property MUST be present and set to "enumeration".
 8severity_level.type = "enumeration"
 9
10# The "description" property is OPTIONAL for an enumeration field.
11# Will default to "" if not specified.
12# The value specified MUST be a string.
13severity_level.description = "Run-time configuration of severity."
14
15# The "default_value" property is OPTIONAL for an enumeration field.
16# Will default to the first enumeration element declared below, if not specified.
17# The value specified MUST be a string that matches one of the enumeration element names
18# specified below.
19severity_level.default_value = "warning"
20
21# For an enumeration field there MUST be at least one enumeration element declared.
22# The name of each element is mapped below to the description of that element.
23severity_level.element.info = "Informational message. Is not considered an error."
24severity_level.element.warning = "Warning message. Is not considered an error."
25severity_level.element.error = "Error message. Is considered an error."
26severity_level.element.failure = "Failure message. Is considered an error."
27
28
29packet_source.type = "enumeration"
30packet_source.description = "Set input mux."
31packet_source.element.streaming = "Process incoming streaming data."
32packet_source.element.dma = "Read packets from DMA."
33packet_source.element.disabled = "Don't send anything."

Note that the second field does not have any default value, meaning that it will automatically default to the first element (streaming).

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 enumeration 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_enumeration.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="conf", mode=REGISTER_MODES["r_w"], description="Configuration register."
32    )
33
34    register.append_enumeration(
35        name="severity_level",
36        description="Run-time configuration of severity.",
37        elements={
38            "info": "Informational message. Is not considered an error.",
39            "warning": "Warning message. Is not considered an error.",
40            "error": "Error message. Is considered an error.",
41            "failure": "Failure message. Is considered an error.",
42        },
43        default_value="warning",
44    )
45
46    register.append_enumeration(
47        name="packet_source",
48        description="Set input mux.",
49        elements={
50            "streaming": "Process incoming streaming data.",
51            "dma": "Read packets from DMA.",
52            "disabled": "Don't send anything.",
53        },
54        default_value="streaming",
55    )
56
57    return register_list
58
59
60def generate(register_list: RegisterList, output_folder: Path) -> None:
61    """
62    Generate the artifacts that we are interested in.
63    """
64    CHeaderGenerator(register_list=register_list, output_folder=output_folder).create()
65
66    CppImplementationGenerator(register_list=register_list, output_folder=output_folder).create()
67    CppInterfaceGenerator(register_list=register_list, output_folder=output_folder).create()
68
69    HtmlPageGenerator(register_list=register_list, output_folder=output_folder).create()
70
71    VhdlRegisterPackageGenerator(register_list=register_list, output_folder=output_folder).create()
72    VhdlRecordPackageGenerator(register_list=register_list, output_folder=output_folder).create()
73
74
75def main(output_folder: Path) -> None:
76    generate(register_list=parse_toml(), output_folder=output_folder / "toml")
77    generate(register_list=create_from_api(), output_folder=output_folder / "api")
78
79
80if __name__ == "__main__":
81    main(output_folder=Path(sys.argv[1]))

See Register.append_enumeration() and the Enumeration class for more Python API details.

Generated code

See below for a description of the code that can be generated when using enumeration 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 enumeration field is documented and the description of each element is included.

See HTML 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 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. The first field is two bits wide, occupying bits 1 and 0, while the second one is only one bit wide, occupying but 3.

  3. VHDL supports enumeration types natively. The elements of the enumeration are exposed to the scope of the package, and all files that include it.

  4. For each enumeration field, there are conversion functions for

    1. Converting from the enumeration type to std_logic_vector.

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

Click to expand/collapse code.
Generated VHDL register package.
  1-- -----------------------------------------------------------------------------
  2-- This file is automatically generated by hdl-registers version 8.0.2-dev.
  3-- Code generator VhdlRegisterPackageGenerator version 2.0.0.
  4-- Generated 2025-05-31 20:51 at Git commit 76c4bba75025.
  5-- Register hash cddf2158e621e8c886df3b685f3035d60205acc1.
  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_conf : 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 'conf' register.
 50  -- Range of the 'severity_level' field.
 51  subtype caesar_conf_severity_level is natural range 1 downto 0;
 52  -- Width of the 'severity_level' field.
 53  constant caesar_conf_severity_level_width : positive := 2;
 54  -- Type for the 'severity_level' field.
 55  type caesar_conf_severity_level_t is (
 56    severity_level_info,
 57    severity_level_warning,
 58    severity_level_error,
 59    severity_level_failure
 60  );
 61  -- Default value of the 'severity_level' field.
 62  constant caesar_conf_severity_level_init : caesar_conf_severity_level_t := severity_level_warning;
 63  -- Type for the 'severity_level' field as an SLV.
 64  subtype caesar_conf_severity_level_slv_t is std_ulogic_vector(1 downto 0);
 65  -- Cast a 'severity_level' field value to SLV.
 66  function to_slv(data : caesar_conf_severity_level_t) return caesar_conf_severity_level_slv_t;
 67  -- Get a 'severity_level' field value from a register value.
 68  function to_caesar_conf_severity_level(data : register_t) return caesar_conf_severity_level_t;
 69
 70  -- Range of the 'packet_source' field.
 71  subtype caesar_conf_packet_source is natural range 3 downto 2;
 72  -- Width of the 'packet_source' field.
 73  constant caesar_conf_packet_source_width : positive := 2;
 74  -- Type for the 'packet_source' field.
 75  type caesar_conf_packet_source_t is (
 76    packet_source_streaming,
 77    packet_source_dma,
 78    packet_source_disabled
 79  );
 80  -- Default value of the 'packet_source' field.
 81  constant caesar_conf_packet_source_init : caesar_conf_packet_source_t := packet_source_streaming;
 82  -- Type for the 'packet_source' field as an SLV.
 83  subtype caesar_conf_packet_source_slv_t is std_ulogic_vector(1 downto 0);
 84  -- Cast a 'packet_source' field value to SLV.
 85  function to_slv(data : caesar_conf_packet_source_t) return caesar_conf_packet_source_slv_t;
 86  -- Get a 'packet_source' field value from a register value.
 87  function to_caesar_conf_packet_source(data : register_t) return caesar_conf_packet_source_t;
 88
 89end package;
 90
 91package body caesar_regs_pkg is
 92
 93  constant caesar_register_map : register_definition_vec_t(caesar_register_range) := (
 94    0 => (index => caesar_conf, mode => r_w, utilized_width => 4)
 95  );
 96
 97  constant caesar_regs_init : caesar_regs_t := (
 98    0 => "00000000000000000000000000000001"
 99  );
100
101  -- Cast a 'severity_level' field value to SLV.
102  function to_slv(data : caesar_conf_severity_level_t) return caesar_conf_severity_level_slv_t is
103    constant data_int : natural := caesar_conf_severity_level_t'pos(data);
104    constant result : caesar_conf_severity_level_slv_t := std_ulogic_vector(
105      to_unsigned(data_int, caesar_conf_severity_level_width)
106    );
107  begin
108    return result;
109  end function;
110
111  -- Get a 'severity_level' field value from a register value.
112  function to_caesar_conf_severity_level(data : register_t) return caesar_conf_severity_level_t is
113    constant field_slv : caesar_conf_severity_level_slv_t := data(caesar_conf_severity_level);
114    constant field_int : natural := to_integer(unsigned(field_slv));
115    constant result : caesar_conf_severity_level_t := caesar_conf_severity_level_t'val(field_int);
116  begin
117    return result;
118  end function;
119
120  -- Cast a 'packet_source' field value to SLV.
121  function to_slv(data : caesar_conf_packet_source_t) return caesar_conf_packet_source_slv_t is
122    constant data_int : natural := caesar_conf_packet_source_t'pos(data);
123    constant result : caesar_conf_packet_source_slv_t := std_ulogic_vector(
124      to_unsigned(data_int, caesar_conf_packet_source_width)
125    );
126  begin
127    return result;
128  end function;
129
130  -- Get a 'packet_source' field value from a register value.
131  function to_caesar_conf_packet_source(data : register_t) return caesar_conf_packet_source_t is
132    constant field_slv : caesar_conf_packet_source_slv_t := data(caesar_conf_packet_source);
133    constant field_int : natural := to_integer(unsigned(field_slv));
134    constant result : caesar_conf_packet_source_t := caesar_conf_packet_source_t'val(field_int);
135  begin
136    return result;
137  end function;
138
139end 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 two enumerations set up in our example: severity_level and packet_source. These are of enumeration types defined in the base register package above.

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

if regs_down.config.packet_source = packet_source_streaming then
  result_valid <= input_valid;
elsif regs_down.config.packet_source = packet_source_dma then
  result_valid <= job_valid;
else
  -- packet_source_disabled
  result_valid <= '0';
end if;
Click to expand/collapse code.
Generated VHDL record package.
  1-- -----------------------------------------------------------------------------
  2-- This file is automatically generated by hdl-registers version 8.0.2-dev.
  3-- Code generator VhdlRecordPackageGenerator version 1.0.0.
  4-- Generated 2025-05-31 20:51 at Git commit 76c4bba75025.
  5-- Register hash cddf2158e621e8c886df3b685f3035d60205acc1.
  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 'conf' register as a record.
 24  type caesar_conf_t is record
 25    severity_level : caesar_conf_severity_level_t;
 26    packet_source : caesar_conf_packet_source_t;
 27  end record;
 28  -- Default value for the 'conf' register as a record.
 29  constant caesar_conf_init : caesar_conf_t := (
 30    severity_level => caesar_conf_severity_level_init,
 31    packet_source => caesar_conf_packet_source_init
 32  );
 33  -- Convert a record of the 'conf' register to SLV.
 34  function to_slv(data : caesar_conf_t) return register_t;
 35  -- Convert an SLV register value to the record for the 'conf' register.
 36  function to_caesar_conf(data : register_t) return caesar_conf_t;
 37
 38  -- -----------------------------------------------------------------------------
 39  -- Below is a record with correctly typed and ranged members for all registers, register arrays
 40  -- and fields that are in the 'down' direction.
 41  -- Record with everything in the 'down' direction.
 42  type caesar_regs_down_t is record
 43    conf : caesar_conf_t;
 44  end record;
 45  -- Default value of the above record.
 46  constant caesar_regs_down_init : caesar_regs_down_t := (
 47    conf => caesar_conf_init
 48  );
 49  -- Convert SLV register list to record with everything in the 'down' direction.
 50  function to_caesar_regs_down(data : caesar_regs_t) return caesar_regs_down_t;
 51
 52  -- ---------------------------------------------------------------------------
 53  -- Below is a record with a status bit for each readable register in the register list.
 54  -- It can be used for the 'reg_was_read' port of a register file wrapper.
 55  -- Combined status mask record for all readable register.
 56  type caesar_reg_was_read_t is record
 57    conf : std_ulogic;
 58  end record;
 59  -- Default value for the above record.
 60  constant caesar_reg_was_read_init : caesar_reg_was_read_t := (
 61    others => '0'
 62  );
 63  -- Convert an SLV 'reg_was_read' from generic register file to the record above.
 64  function to_caesar_reg_was_read(
 65    data : caesar_reg_was_accessed_t
 66  ) return caesar_reg_was_read_t;
 67
 68  -- ---------------------------------------------------------------------------
 69  -- Below is a record with a status bit for each writeable register in the register list.
 70  -- It can be used for the 'reg_was_written' port of a register file wrapper.
 71  -- Combined status mask record for all writeable register.
 72  type caesar_reg_was_written_t is record
 73    conf : std_ulogic;
 74  end record;
 75  -- Default value for the above record.
 76  constant caesar_reg_was_written_init : caesar_reg_was_written_t := (
 77    others => '0'
 78  );
 79  -- Convert an SLV 'reg_was_written' from generic register file to the record above.
 80  function to_caesar_reg_was_written(
 81    data : caesar_reg_was_accessed_t
 82  ) return caesar_reg_was_written_t;
 83
 84end package;
 85
 86package body caesar_register_record_pkg is
 87
 88  function to_slv(data : caesar_conf_t) return register_t is
 89    variable result : register_t := (others => '-');
 90  begin
 91    result(caesar_conf_severity_level) := to_slv(data.severity_level);
 92    result(caesar_conf_packet_source) := to_slv(data.packet_source);
 93
 94    return result;
 95  end function;
 96
 97  function to_caesar_conf(data : register_t) return caesar_conf_t is
 98    variable result : caesar_conf_t := caesar_conf_init;
 99  begin
100    result.severity_level := to_caesar_conf_severity_level(data);
101    result.packet_source := to_caesar_conf_packet_source(data);
102
103    return result;
104  end function;
105
106  function to_caesar_regs_down(data : caesar_regs_t) return caesar_regs_down_t is
107    variable result : caesar_regs_down_t := caesar_regs_down_init;
108  begin
109    result.conf := to_caesar_conf(data(caesar_conf));
110
111    return result;
112  end function;
113
114  function to_caesar_reg_was_read(
115    data : caesar_reg_was_accessed_t
116  ) return caesar_reg_was_read_t is
117    variable result : caesar_reg_was_read_t := caesar_reg_was_read_init;
118  begin
119    result.conf := data(caesar_conf);
120
121    return result;
122  end function;
123
124  function to_caesar_reg_was_written(
125    data : caesar_reg_was_accessed_t
126  ) return caesar_reg_was_written_t is
127    variable result : caesar_reg_was_written_t := caesar_reg_was_written_init;
128  begin
129    result.conf := data(caesar_conf);
130
131    return result;
132  end function;
133
134end 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++ generator for more details and an example of how the excluded file might look.

C++ interface header

Some interesting things to notice in the interface header:

  1. The valid enumeration values are defined using a C++ enum declaration in the namespace of each field.

  2. The setters and getters for each field value use the enumeration type as argument or return value.

Click to expand/collapse code.
Generated C++ interface class code.
  1// -----------------------------------------------------------------------------
  2// This file is automatically generated by hdl-registers version 8.0.2-dev.
  3// Code generator CppInterfaceGenerator version 1.0.0.
  4// Generated 2025-05-31 20:51 at Git commit 76c4bba75025.
  5// Register hash cddf2158e621e8c886df3b685f3035d60205acc1.
  6// -----------------------------------------------------------------------------
  7
  8#pragma once
  9
 10#include <sstream>
 11#include <cstdint>
 12#include <cstdlib>
 13
 14namespace fpga_regs
 15{
 16
 17  namespace caesar
 18  {
 19
 20    // Attributes for the 'conf' register.
 21    namespace conf {
 22      // Attributes for the 'severity_level' field.
 23      namespace severity_level
 24      {
 25        // The number of bits that the field occupies.
 26        static const size_t width = 2;
 27        // The bit index of the lowest bit in the field.
 28        static const size_t shift = 0;
 29        // The bit mask of the field, at index zero.
 30        static const uint32_t mask_at_base = (1uLL << width) - 1;
 31        // The bit mask of the field, at the field's bit index.
 32        static const uint32_t mask_shifted = mask_at_base << shift;
 33
 34        // The valid elements for this enumeration field.
 35        enum Enumeration
 36        {
 37          info = 0,
 38          warning = 1,
 39          error = 2,
 40          failure = 3,
 41        };
 42
 43        // Initial value of the field at device startup/reset.
 44        static const Enumeration default_value = Enumeration::warning;
 45        // Raw representation of the initial value, at the the field's bit index.
 46        static const uint32_t default_value_raw = 1uL << shift;
 47      }
 48
 49      // Attributes for the 'packet_source' field.
 50      namespace packet_source
 51      {
 52        // The number of bits that the field occupies.
 53        static const size_t width = 2;
 54        // The bit index of the lowest bit in the field.
 55        static const size_t shift = 2;
 56        // The bit mask of the field, at index zero.
 57        static const uint32_t mask_at_base = (1uLL << width) - 1;
 58        // The bit mask of the field, at the field's bit index.
 59        static const uint32_t mask_shifted = mask_at_base << shift;
 60
 61        // The valid elements for this enumeration field.
 62        enum Enumeration
 63        {
 64          streaming = 0,
 65          dma = 1,
 66          disabled = 2,
 67        };
 68
 69        // Initial value of the field at device startup/reset.
 70        static const Enumeration default_value = Enumeration::streaming;
 71        // Raw representation of the initial value, at the the field's bit index.
 72        static const uint32_t default_value_raw = 0uL << shift;
 73      }
 74
 75      // Struct that holds the value of each field in the register,
 76      // in a native C++ representation.
 77      struct Value {
 78        severity_level::Enumeration severity_level;
 79        packet_source::Enumeration packet_source;
 80      };
 81      // Initial value of the register at device startup/reset.
 82      const Value default_value = {
 83        severity_level::default_value,
 84        packet_source::default_value,
 85      };
 86    }
 87
 88  } // namespace caesar
 89
 90  class ICaesar
 91  {
 92  public:
 93    // Number of registers within this register list.
 94    static const size_t num_registers = 1uL;
 95
 96    virtual ~ICaesar() {}
 97
 98    // -------------------------------------------------------------------------
 99    // Methods for the 'conf' register.
100    // Mode 'Read, Write'.
101    // -------------------------------------------------------------------------
102    // Read the whole register value over the register bus.
103    virtual caesar::conf::Value get_conf() const = 0;
104
105    // Read the whole register value over the register bus.
106    // This method returns the raw register value without any type conversion.
107    virtual uint32_t get_conf_raw() const = 0;
108
109    // Read the register and slice out the 'severity_level' field value.
110    virtual caesar::conf::severity_level::Enumeration get_conf_severity_level() const = 0;
111
112    // Read the register and slice out the 'packet_source' field value.
113    virtual caesar::conf::packet_source::Enumeration get_conf_packet_source() const = 0;
114
115    // Write the whole register value over the register bus.
116    virtual void set_conf(
117      caesar::conf::Value register_value
118    ) const = 0;
119
120    // Write the whole register value over the register bus.
121    // This method takes a raw register value and does not perform any type conversion.
122    virtual void set_conf_raw(
123      uint32_t register_value
124    ) const = 0;
125
126    // Write the 'severity_level' field value.
127    // Will read-modify-write the register.
128    virtual void set_conf_severity_level(
129      caesar::conf::severity_level::Enumeration field_value
130    ) const = 0;
131
132    // Write the 'packet_source' field value.
133    // Will read-modify-write the register.
134    virtual void set_conf_packet_source(
135      caesar::conf::packet_source::Enumeration field_value
136    ) const = 0;
137    // -------------------------------------------------------------------------
138  };
139
140} // namespace fpga_regs

C++ implementation

Note that each getter casts a uint32_t value read from the register bus to the enumeration type.

Click to expand/collapse code.
Generated C++ class implementation code.
  1// -----------------------------------------------------------------------------
  2// This file is automatically generated by hdl-registers version 8.0.2-dev.
  3// Code generator CppImplementationGenerator version 2.0.2.
  4// Generated 2025-05-31 20:51 at Git commit 76c4bba75025.
  5// Register hash cddf2158e621e8c886df3b685f3035d60205acc1.
  6// -----------------------------------------------------------------------------
  7
  8#include "include/caesar.h"
  9
 10namespace fpga_regs
 11{
 12
 13// Macros called by the register code below to check for runtime errors.
 14#ifdef NO_REGISTER_SETTER_ASSERT
 15  #define _SETTER_ASSERT_TRUE(expression, message) ((void)0)
 16#else
 17  #define _SETTER_ASSERT_TRUE(expression, message) (_ASSERT_TRUE(expression, message))
 18#endif
 19
 20#ifdef NO_REGISTER_GETTER_ASSERT
 21  #define _GETTER_ASSERT_TRUE(expression, message) ((void)0)
 22#else
 23  #define _GETTER_ASSERT_TRUE(expression, message) (_ASSERT_TRUE(expression, message))
 24#endif
 25
 26#ifdef NO_REGISTER_ARRAY_INDEX_ASSERT
 27  #define _ARRAY_INDEX_ASSERT_TRUE(expression, message) ((void)0)
 28#else
 29  #define _ARRAY_INDEX_ASSERT_TRUE(expression, message) (_ASSERT_TRUE(expression, message))
 30#endif
 31
 32// Base macro called by the other macros.
 33#define _ASSERT_TRUE(expression, message)                                                      \
 34  {                                                                                            \
 35    if (!static_cast<bool>(expression)) {                                                      \
 36      std::ostringstream diagnostics;                                                          \
 37      diagnostics << "caesar.cpp:" << __LINE__ << ": " << message << ".";                      \
 38      std::string diagnostic_message = diagnostics.str();                                      \
 39      m_assertion_handler(&diagnostic_message);                                                \
 40    }                                                                                          \
 41  }
 42
 43  Caesar::Caesar(uintptr_t base_address, bool (*assertion_handler) (const std::string*))
 44      : m_registers(reinterpret_cast<volatile uint32_t *>(base_address)),
 45        m_assertion_handler(assertion_handler)
 46  {
 47    // Empty
 48  }
 49
 50  // ---------------------------------------------------------------------------
 51  // Methods for the 'conf' register.
 52  // Mode 'Read, Write'.
 53  // ---------------------------------------------------------------------------
 54  // Read the whole register value over the register bus.
 55  caesar::conf::Value Caesar::get_conf() const
 56  {
 57    const uint32_t raw_value = get_conf_raw();
 58
 59    const caesar::conf::severity_level::Enumeration severity_level_value = get_conf_severity_level_from_raw(raw_value);
 60    const caesar::conf::packet_source::Enumeration packet_source_value = get_conf_packet_source_from_raw(raw_value);
 61
 62    return {severity_level_value, packet_source_value};
 63  }
 64
 65  // Read the whole register value over the register bus.
 66  // This method returns the raw register value without any type conversion.
 67  uint32_t Caesar::get_conf_raw() const
 68  {
 69    const size_t index = 0;
 70    const uint32_t raw_value = m_registers[index];
 71
 72    return raw_value;
 73  }
 74
 75  // Read the register and slice out the 'severity_level' field value.
 76  caesar::conf::severity_level::Enumeration Caesar::get_conf_severity_level() const
 77  {
 78    const uint32_t raw_value = get_conf_raw();
 79
 80    return get_conf_severity_level_from_raw(raw_value);
 81  }
 82
 83  // Slice out the 'severity_level' field value from a given raw register value.
 84  // Performs no operation on the register bus.
 85  caesar::conf::severity_level::Enumeration Caesar::get_conf_severity_level_from_raw(
 86    uint32_t register_value
 87  ) const
 88  {
 89    const uint32_t result_masked = register_value & caesar::conf::severity_level::mask_shifted;
 90    const uint32_t result_shifted = result_masked >> caesar::conf::severity_level::shift;
 91
 92    // "Cast" to the enum type.
 93    const auto field_value = caesar::conf::severity_level::Enumeration(result_shifted);
 94
 95    return field_value;
 96  }
 97
 98  // Read the register and slice out the 'packet_source' field value.
 99  caesar::conf::packet_source::Enumeration Caesar::get_conf_packet_source() const
100  {
101    const uint32_t raw_value = get_conf_raw();
102
103    return get_conf_packet_source_from_raw(raw_value);
104  }
105
106  // Slice out the 'packet_source' field value from a given raw register value.
107  // Performs no operation on the register bus.
108  caesar::conf::packet_source::Enumeration Caesar::get_conf_packet_source_from_raw(
109    uint32_t register_value
110  ) const
111  {
112    const uint32_t result_masked = register_value & caesar::conf::packet_source::mask_shifted;
113    const uint32_t result_shifted = result_masked >> caesar::conf::packet_source::shift;
114
115    // "Cast" to the enum type.
116    const auto field_value = caesar::conf::packet_source::Enumeration(result_shifted);
117
118    _GETTER_ASSERT_TRUE(
119      field_value <= 2,
120      "Got 'packet_source' value out of range: " << field_value
121    );
122
123    return field_value;
124  }
125
126  // Write the whole register value over the register bus.
127  void Caesar::set_conf(
128    caesar::conf::Value register_value
129  ) const
130  {
131    const uint32_t severity_level_value = get_conf_severity_level_to_raw(register_value.severity_level);
132    const uint32_t packet_source_value = get_conf_packet_source_to_raw(register_value.packet_source);
133    const uint32_t raw_value = severity_level_value | packet_source_value;
134
135    set_conf_raw(raw_value);
136  }
137
138  // Write the whole register value over the register bus.
139  // This method takes a raw register value and does not perform any type conversion.
140  void Caesar::set_conf_raw(
141    uint32_t register_value
142  ) const
143  {
144    const size_t index = 0;
145    m_registers[index] = register_value;
146  }
147
148  // Write the 'severity_level' field value.
149  // Will read-modify-write the register.
150  void Caesar::set_conf_severity_level(
151    caesar::conf::severity_level::Enumeration field_value
152  ) const
153  {
154    const size_t index = 0;
155
156    const uint32_t raw_value = m_registers[index];
157    const uint32_t mask_shifted_inverse = ~caesar::conf::severity_level::mask_shifted;
158    const uint32_t base_value = raw_value & mask_shifted_inverse;
159
160    const uint32_t field_value_raw = get_conf_severity_level_to_raw(field_value);
161    const uint32_t register_value = base_value | field_value_raw;
162
163    m_registers[index] = register_value;
164  }
165
166  // Get the raw representation of a given 'severity_level' field value.
167  // Performs no operation on the register bus.
168  uint32_t Caesar::get_conf_severity_level_to_raw(caesar::conf::severity_level::Enumeration field_value) const
169  {
170    _SETTER_ASSERT_TRUE(
171      field_value <= 3,
172      "Got 'severity_level' value out of range: " << field_value
173    );
174
175    const uint32_t field_value_casted = static_cast<uint32_t>(field_value);
176    const uint32_t field_value_shifted = field_value_casted << caesar::conf::severity_level::shift;
177
178    return field_value_shifted;
179  }
180
181  // Write the 'packet_source' field value.
182  // Will read-modify-write the register.
183  void Caesar::set_conf_packet_source(
184    caesar::conf::packet_source::Enumeration field_value
185  ) const
186  {
187    const size_t index = 0;
188
189    const uint32_t raw_value = m_registers[index];
190    const uint32_t mask_shifted_inverse = ~caesar::conf::packet_source::mask_shifted;
191    const uint32_t base_value = raw_value & mask_shifted_inverse;
192
193    const uint32_t field_value_raw = get_conf_packet_source_to_raw(field_value);
194    const uint32_t register_value = base_value | field_value_raw;
195
196    m_registers[index] = register_value;
197  }
198
199  // Get the raw representation of a given 'packet_source' field value.
200  // Performs no operation on the register bus.
201  uint32_t Caesar::get_conf_packet_source_to_raw(caesar::conf::packet_source::Enumeration field_value) const
202  {
203    _SETTER_ASSERT_TRUE(
204      field_value <= 2,
205      "Got 'packet_source' value out of range: " << field_value
206    );
207
208    const uint32_t field_value_casted = static_cast<uint32_t>(field_value);
209    const uint32_t field_value_shifted = field_value_casted << caesar::conf::packet_source::shift;
210
211    return field_value_shifted;
212  }
213  // ---------------------------------------------------------------------------
214
215} // 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. Note how the valid enumeration values are defined using a C enum declaration.

Click to expand/collapse code.
Generated C code.
 1// -----------------------------------------------------------------------------
 2// This file is automatically generated by hdl-registers version 8.0.2-dev.
 3// Code generator CHeaderGenerator version 1.0.0.
 4// Generated 2025-05-31 20:51 at Git commit 76c4bba75025.
 5// Register hash cddf2158e621e8c886df3b685f3035d60205acc1.
 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 conf;
20} caesar_regs_t;
21
22// Address of the 'conf' register.
23// Mode 'Read, Write'.
24#define CAESAR_CONF_INDEX (0u)
25#define CAESAR_CONF_ADDR (4u * CAESAR_CONF_INDEX)
26// Attributes for the 'severity_level' field in the 'conf' register.
27#define CAESAR_CONF_SEVERITY_LEVEL_SHIFT (0u)
28#define CAESAR_CONF_SEVERITY_LEVEL_MASK (0b11u << 0u)
29#define CAESAR_CONF_SEVERITY_LEVEL_MASK_INVERSE (~CAESAR_CONF_SEVERITY_LEVEL_MASK)
30enum CaesarConfSeverityLevel
31{
32  CAESAR_CONF_SEVERITY_LEVEL_INFO = 0,
33  CAESAR_CONF_SEVERITY_LEVEL_WARNING = 1,
34  CAESAR_CONF_SEVERITY_LEVEL_ERROR = 2,
35  CAESAR_CONF_SEVERITY_LEVEL_FAILURE = 3,
36};
37// Attributes for the 'packet_source' field in the 'conf' register.
38#define CAESAR_CONF_PACKET_SOURCE_SHIFT (2u)
39#define CAESAR_CONF_PACKET_SOURCE_MASK (0b11u << 2u)
40#define CAESAR_CONF_PACKET_SOURCE_MASK_INVERSE (~CAESAR_CONF_PACKET_SOURCE_MASK)
41enum CaesarConfPacketSource
42{
43  CAESAR_CONF_PACKET_SOURCE_STREAMING = 0,
44  CAESAR_CONF_PACKET_SOURCE_DMA = 1,
45  CAESAR_CONF_PACKET_SOURCE_DISABLED = 2,
46};
47
48#endif // CAESAR_REGS_H