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[config]
 2
 3mode = "r_w"
 4description = "Configuration register."
 5
 6# This will allocate an enumeration field named "severity_level" in the "config" register.
 7[config.severity_level]
 8
 9# The "type" property MUST be present and set to "enumeration".
10type = "enumeration"
11
12# The "description" property is OPTIONAL for an enumeration field.
13# Will default to "" if not specified.
14# The value specified MUST be a string.
15description = "Run-time configuration of severity."
16
17# The "default_value" property is OPTIONAL for an enumeration field.
18# Will default to the first enumeration element declared below, if not specified.
19# The value specified MUST be a string that matches one of the enumeration element names
20# specified below.
21default_value = "warning"
22
23# For an enumeration field there MUST be at least one enumeration element declared.
24# The name of each element is mapped below to the description of that element.
25element.info = "Informational message. Is not considered an error."
26element.warning = "Warning message. Is not considered an error."
27element.error = "Error message. Is considered an error."
28element.failure = "Failure message. Is considered an error."
29
30
31[config.packet_source]
32
33type = "enumeration"
34description = "Set input mux."
35
36element.streaming = "Process incoming streaming data."
37element.dma = "Read packets from DMA."
38element.none = "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.
 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(name="caesar", toml_file=THIS_DIR.parent / "toml" / "field_enumeration.toml")
24
25
26def create_from_api() -> RegisterList:
27    """
28    Alternative method: Create the register list by using the Python API.
29    """
30    register_list = RegisterList(name="caesar")
31
32    register = register_list.append_register(
33        name="config", mode=REGISTER_MODES["r_w"], description="Configuration register."
34    )
35
36    register.append_enumeration(
37        name="severity_level",
38        description="Run-time configuration of severity.",
39        elements={
40            "info": "Informational message. Is not considered an error.",
41            "warning": "Warning message. Is not considered an error.",
42            "error": "Error message. Is considered an error.",
43            "failure": "Failure message. Is considered an error.",
44        },
45        default_value="warning",
46    )
47
48    register.append_enumeration(
49        name="packet_source",
50        description="Set input mux.",
51        elements={
52            "streaming": "Process incoming streaming data.",
53            "dma": "Read packets from DMA.",
54            "none": "Don't send anything.",
55        },
56        default_value="streaming",
57    )
58
59    return register_list
60
61
62def generate(register_list: RegisterList, output_folder: Path):
63    """
64    Generate the artifacts that we are interested in.
65    """
66    CHeaderGenerator(register_list=register_list, output_folder=output_folder).create()
67
68    CppImplementationGenerator(register_list=register_list, output_folder=output_folder).create()
69    CppInterfaceGenerator(register_list=register_list, output_folder=output_folder).create()
70
71    HtmlPageGenerator(register_list=register_list, output_folder=output_folder).create()
72
73    VhdlRegisterPackageGenerator(register_list=register_list, output_folder=output_folder).create()
74    VhdlRecordPackageGenerator(register_list=register_list, output_folder=output_folder).create()
75
76
77def main(output_folder: Path):
78    generate(register_list=parse_toml(), output_folder=output_folder / "toml")
79    generate(register_list=create_from_api(), output_folder=output_folder / "api")
80
81
82if __name__ == "__main__":
83    main(output_folder=Path(sys.argv[1]))

See Register.append_enumeration() 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 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. 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-- This file is automatically generated by hdl-registers version 6.2.1-dev.
  2-- Code generator VhdlRegisterPackageGenerator version 1.0.0.
  3-- Generated 2024-12-19 20:52 at commit cd01ff93f646632c.
  4-- Register hash c2412eacf08bbf54a4f274f2d5acaec28407a34e.
  5
  6library ieee;
  7use ieee.std_logic_1164.all;
  8use ieee.numeric_std.all;
  9use ieee.fixed_pkg.all;
 10
 11library reg_file;
 12use reg_file.reg_file_pkg.all;
 13
 14
 15package caesar_regs_pkg is
 16
 17  -- ---------------------------------------------------------------------------
 18  -- The valid range of register indexes.
 19  subtype caesar_reg_range is natural range 0 to 0;
 20
 21  -- Register indexes, within the list of registers.
 22  constant caesar_config : natural := 0;
 23
 24  -- Declare 'reg_map' and 'regs_init' constants here but define them in body (deferred constants).
 25  -- So that functions have been elaborated when they are called.
 26  -- Needed for ModelSim compilation to pass.
 27
 28  -- To be used as the 'regs' generic of 'axi_lite_reg_file.vhd'.
 29  constant caesar_reg_map : reg_definition_vec_t(caesar_reg_range);
 30
 31  -- To be used for the 'regs_up' and 'regs_down' ports of 'axi_lite_reg_file.vhd'.
 32  subtype caesar_regs_t is reg_vec_t(caesar_reg_range);
 33  -- To be used as the 'default_values' generic of 'axi_lite_reg_file.vhd'.
 34  constant caesar_regs_init : caesar_regs_t;
 35
 36  -- To be used for the 'reg_was_read' and 'reg_was_written' ports of 'axi_lite_reg_file.vhd'.
 37  subtype caesar_reg_was_accessed_t is std_ulogic_vector(caesar_reg_range);
 38
 39  -- -----------------------------------------------------------------------------
 40  -- Fields in the 'config' register.
 41  -- Range of the 'severity_level' field.
 42  subtype caesar_config_severity_level is natural range 1 downto 0;
 43  -- Width of the 'severity_level' field.
 44  constant caesar_config_severity_level_width : positive := 2;
 45  -- Type for the 'severity_level' field.
 46  type caesar_config_severity_level_t is (
 47    severity_level_info,
 48    severity_level_warning,
 49    severity_level_error,
 50    severity_level_failure
 51  );
 52  -- Default value of the 'severity_level' field.
 53  constant caesar_config_severity_level_init : caesar_config_severity_level_t := severity_level_warning;
 54  -- Type for the 'severity_level' field as an SLV.
 55  subtype caesar_config_severity_level_slv_t is std_ulogic_vector(1 downto 0);
 56  -- Cast a 'severity_level' field value to SLV.
 57  function to_slv(data : caesar_config_severity_level_t) return caesar_config_severity_level_slv_t;
 58  -- Get a 'severity_level' field value from a register value.
 59  function to_caesar_config_severity_level(data : reg_t) return caesar_config_severity_level_t;
 60
 61  -- Range of the 'packet_source' field.
 62  subtype caesar_config_packet_source is natural range 3 downto 2;
 63  -- Width of the 'packet_source' field.
 64  constant caesar_config_packet_source_width : positive := 2;
 65  -- Type for the 'packet_source' field.
 66  type caesar_config_packet_source_t is (
 67    packet_source_streaming,
 68    packet_source_dma,
 69    packet_source_none
 70  );
 71  -- Default value of the 'packet_source' field.
 72  constant caesar_config_packet_source_init : caesar_config_packet_source_t := packet_source_streaming;
 73  -- Type for the 'packet_source' field as an SLV.
 74  subtype caesar_config_packet_source_slv_t is std_ulogic_vector(1 downto 0);
 75  -- Cast a 'packet_source' field value to SLV.
 76  function to_slv(data : caesar_config_packet_source_t) return caesar_config_packet_source_slv_t;
 77  -- Get a 'packet_source' field value from a register value.
 78  function to_caesar_config_packet_source(data : reg_t) return caesar_config_packet_source_t;
 79
 80end package;
 81
 82package body caesar_regs_pkg is
 83
 84  constant caesar_reg_map : reg_definition_vec_t(caesar_reg_range) := (
 85    0 => (idx => caesar_config, reg_type => r_w)
 86  );
 87
 88  constant caesar_regs_init : caesar_regs_t := (
 89    0 => "00000000000000000000000000000001"
 90  );
 91
 92  -- Cast a 'severity_level' field value to SLV.
 93  function to_slv(data : caesar_config_severity_level_t) return caesar_config_severity_level_slv_t is
 94    constant data_int : natural := caesar_config_severity_level_t'pos(data);
 95    constant result : caesar_config_severity_level_slv_t := std_ulogic_vector(
 96      to_unsigned(data_int, caesar_config_severity_level_width)
 97    );
 98  begin
 99    return result;
100  end function;
101
102  -- Get a 'severity_level' field value from a register value.
103  function to_caesar_config_severity_level(data : reg_t) return caesar_config_severity_level_t is
104    constant field_slv : caesar_config_severity_level_slv_t := data(caesar_config_severity_level);
105    constant field_int : natural := to_integer(unsigned(field_slv));
106    constant result : caesar_config_severity_level_t := caesar_config_severity_level_t'val(field_int);
107  begin
108    return result;
109  end function;
110
111  -- Cast a 'packet_source' field value to SLV.
112  function to_slv(data : caesar_config_packet_source_t) return caesar_config_packet_source_slv_t is
113    constant data_int : natural := caesar_config_packet_source_t'pos(data);
114    constant result : caesar_config_packet_source_slv_t := std_ulogic_vector(
115      to_unsigned(data_int, caesar_config_packet_source_width)
116    );
117  begin
118    return result;
119  end function;
120
121  -- Get a 'packet_source' field value from a register value.
122  function to_caesar_config_packet_source(data : reg_t) return caesar_config_packet_source_t is
123    constant field_slv : caesar_config_packet_source_slv_t := data(caesar_config_packet_source);
124    constant field_int : natural := to_integer(unsigned(field_slv));
125    constant result : caesar_config_packet_source_t := caesar_config_packet_source_t'val(field_int);
126  begin
127    return result;
128  end function;
129
130end 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_none
  result_valid <= '0';
end if;
Click to expand/collapse code.
Generated VHDL record package.
  1-- This file is automatically generated by hdl-registers version 6.2.1-dev.
  2-- Code generator VhdlRecordPackageGenerator version 1.0.0.
  3-- Generated 2024-12-19 20:52 at commit cd01ff93f646632c.
  4-- Register hash c2412eacf08bbf54a4f274f2d5acaec28407a34e.
  5
  6library ieee;
  7use ieee.fixed_pkg.all;
  8use ieee.std_logic_1164.all;
  9use ieee.numeric_std.all;
 10
 11library reg_file;
 12use reg_file.reg_file_pkg.reg_t;
 13
 14use work.caesar_regs_pkg.all;
 15
 16
 17package caesar_register_record_pkg is
 18
 19  -- -----------------------------------------------------------------------------
 20  -- Record with correctly-typed members for each field in each register.
 21  -- Fields in the 'config' register as a record.
 22  type caesar_config_t is record
 23    severity_level : caesar_config_severity_level_t;
 24    packet_source : caesar_config_packet_source_t;
 25  end record;
 26  -- Default value for the 'config' register as a record.
 27  constant caesar_config_init : caesar_config_t := (
 28    severity_level => caesar_config_severity_level_init,
 29    packet_source => caesar_config_packet_source_init
 30  );
 31  -- Convert a record of the 'config' register to SLV.
 32  function to_slv(data : caesar_config_t) return reg_t;
 33  -- Convert an SLV register value to the record for the 'config' register.
 34  function to_caesar_config(data : reg_t) return caesar_config_t;
 35
 36  -- -----------------------------------------------------------------------------
 37  -- Below is a record with correctly typed and ranged members for all registers, register arrays
 38  -- and fields that are in the 'down' direction.
 39  -- Record with everything in the 'down' direction.
 40  type caesar_regs_down_t is record
 41    config : caesar_config_t;
 42  end record;
 43  -- Default value of the above record.
 44  constant caesar_regs_down_init : caesar_regs_down_t := (
 45    config => caesar_config_init
 46  );
 47  -- Convert SLV register list to record with everything in the 'down' direction.
 48  function to_caesar_regs_down(data : caesar_regs_t) return caesar_regs_down_t;
 49
 50  -- ---------------------------------------------------------------------------
 51  -- Below is a record with a status bit for each readable register in the register map.
 52  -- It can be used for the 'reg_was_read' port of a register file wrapper.
 53  -- Combined status mask record for all readable register.
 54  type caesar_reg_was_read_t is record
 55    config : std_ulogic;
 56  end record;
 57  -- Default value for the above record.
 58  constant caesar_reg_was_read_init : caesar_reg_was_read_t := (
 59    others => '0'
 60  );
 61  -- Convert an SLV 'reg_was_read' from generic register file to the record above.
 62  function to_caesar_reg_was_read(
 63    data : caesar_reg_was_accessed_t
 64  ) return caesar_reg_was_read_t;
 65
 66  -- ---------------------------------------------------------------------------
 67  -- Below is a record with a status bit for each writeable register in the register map.
 68  -- It can be used for the 'reg_was_written' port of a register file wrapper.
 69  -- Combined status mask record for all writeable register.
 70  type caesar_reg_was_written_t is record
 71    config : std_ulogic;
 72  end record;
 73  -- Default value for the above record.
 74  constant caesar_reg_was_written_init : caesar_reg_was_written_t := (
 75    others => '0'
 76  );
 77  -- Convert an SLV 'reg_was_written' from generic register file to the record above.
 78  function to_caesar_reg_was_written(
 79    data : caesar_reg_was_accessed_t
 80  ) return caesar_reg_was_written_t;
 81
 82end package;
 83
 84package body caesar_register_record_pkg is
 85
 86  function to_slv(data : caesar_config_t) return reg_t is
 87    variable result : reg_t := (others => '-');
 88  begin
 89    result(caesar_config_severity_level) := to_slv(data.severity_level);
 90    result(caesar_config_packet_source) := to_slv(data.packet_source);
 91
 92    return result;
 93  end function;
 94
 95  function to_caesar_config(data : reg_t) return caesar_config_t is
 96    variable result : caesar_config_t := caesar_config_init;
 97  begin
 98    result.severity_level := to_caesar_config_severity_level(data);
 99    result.packet_source := to_caesar_config_packet_source(data);
100
101    return result;
102  end function;
103
104  function to_caesar_regs_down(data : caesar_regs_t) return caesar_regs_down_t is
105    variable result : caesar_regs_down_t := caesar_regs_down_init;
106  begin
107    result.config := to_caesar_config(data(caesar_config));
108
109    return result;
110  end function;
111
112  function to_caesar_reg_was_read(
113    data : caesar_reg_was_accessed_t
114  ) return caesar_reg_was_read_t is
115    variable result : caesar_reg_was_read_t := caesar_reg_was_read_init;
116  begin
117    result.config := data(caesar_config);
118
119    return result;
120  end function;
121
122  function to_caesar_reg_was_written(
123    data : caesar_reg_was_accessed_t
124  ) return caesar_reg_was_written_t is
125    variable result : caesar_reg_was_written_t := caesar_reg_was_written_init;
126  begin
127    result.config := data(caesar_config);
128
129    return result;
130  end function;
131
132end 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

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// This file is automatically generated by hdl-registers version 6.2.1-dev.
  2// Code generator CppInterfaceGenerator version 1.0.0.
  3// Generated 2024-12-19 20:52 at commit cd01ff93f646632c.
  4// Register hash c2412eacf08bbf54a4f274f2d5acaec28407a34e.
  5
  6#pragma once
  7
  8#include <sstream>
  9#include <cstdint>
 10#include <cstdlib>
 11
 12namespace fpga_regs
 13{
 14
 15  // Attributes for the 'severity_level' field in the 'config' register.
 16  namespace caesar::config::severity_level
 17  {
 18    static const auto width = 2;
 19    enum Enumeration
 20    {
 21      info = 0,
 22      warning = 1,
 23      error = 2,
 24      failure = 3,
 25    };
 26    static const auto default_value = Enumeration::warning;
 27  }
 28  // Attributes for the 'packet_source' field in the 'config' register.
 29  namespace caesar::config::packet_source
 30  {
 31    static const auto width = 2;
 32    enum Enumeration
 33    {
 34      streaming = 0,
 35      dma = 1,
 36      none = 2,
 37    };
 38    static const auto default_value = Enumeration::streaming;
 39  }
 40
 41  class ICaesar
 42  {
 43  public:
 44    // Number of registers within this register map.
 45    static const size_t num_registers = 1uL;
 46
 47    virtual ~ICaesar() {}
 48
 49    // -------------------------------------------------------------------------
 50    // Methods for the 'config' register. Mode 'Read, Write'.
 51
 52    // Getter that will read the whole register's value over the register bus.
 53    virtual uint32_t get_config() const = 0;
 54
 55    // Setter that will write the whole register's value over the register bus.
 56    virtual void set_config(
 57      uint32_t register_value
 58    ) const = 0;
 59
 60    // Getter for the 'severity_level' field in the 'config' register,
 61    // which will read register value over the register bus.
 62    virtual caesar::config::severity_level::Enumeration get_config_severity_level() const = 0;
 63    // Getter for the 'severity_level' field in the 'config' register,
 64    // given a register value.
 65    virtual caesar::config::severity_level::Enumeration get_config_severity_level_from_value(
 66      uint32_t register_value
 67    ) const = 0;
 68    // Setter for the 'severity_level' field in the 'config' register,
 69    // which will read-modify-write over the register bus.
 70    virtual void set_config_severity_level(
 71      caesar::config::severity_level::Enumeration field_value
 72    ) const = 0;
 73    // Setter for the 'severity_level' field in the 'config' register,
 74    // given a register value, which will return an updated value.
 75    virtual uint32_t set_config_severity_level_from_value(
 76      uint32_t register_value,
 77      caesar::config::severity_level::Enumeration field_value
 78    ) const = 0;
 79
 80    // Getter for the 'packet_source' field in the 'config' register,
 81    // which will read register value over the register bus.
 82    virtual caesar::config::packet_source::Enumeration get_config_packet_source() const = 0;
 83    // Getter for the 'packet_source' field in the 'config' register,
 84    // given a register value.
 85    virtual caesar::config::packet_source::Enumeration get_config_packet_source_from_value(
 86      uint32_t register_value
 87    ) const = 0;
 88    // Setter for the 'packet_source' field in the 'config' register,
 89    // which will read-modify-write over the register bus.
 90    virtual void set_config_packet_source(
 91      caesar::config::packet_source::Enumeration field_value
 92    ) const = 0;
 93    // Setter for the 'packet_source' field in the 'config' register,
 94    // given a register value, which will return an updated value.
 95    virtual uint32_t set_config_packet_source_from_value(
 96      uint32_t register_value,
 97      caesar::config::packet_source::Enumeration field_value
 98    ) const = 0;
 99
100  };
101
102} /* 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// This file is automatically generated by hdl-registers version 6.2.1-dev.
  2// Code generator CppImplementationGenerator version 2.0.0.
  3// Generated 2024-12-19 20:52 at commit cd01ff93f646632c.
  4// Register hash c2412eacf08bbf54a4f274f2d5acaec28407a34e.
  5
  6#include "include/caesar.h"
  7
  8namespace fpga_regs
  9{
 10
 11#ifdef NO_REGISTER_SETTER_ASSERT
 12
 13#define _SETTER_ASSERT_TRUE(expression, message) ((void)0)
 14
 15#else // Not NO_REGISTER_SETTER_ASSERT.
 16
 17// This macro is called by the register code to check for runtime errors.
 18#define _SETTER_ASSERT_TRUE(expression, message)                                 \
 19  {                                                                              \
 20    if (!static_cast<bool>(expression)) {                                        \
 21      std::ostringstream diagnostics;                                            \
 22      diagnostics << "Tried to set value out of range in " << __FILE__ << ":"    \
 23                  << __LINE__ << ", message: " << message << ".";                \
 24      std::string diagnostic_message = diagnostics.str();                        \
 25      _assert_failed(&diagnostic_message);                                       \
 26    }                                                                            \
 27  }
 28
 29#endif // NO_REGISTER_SETTER_ASSERT.
 30
 31#ifdef NO_REGISTER_GETTER_ASSERT
 32
 33#define _GETTER_ASSERT_TRUE(expression, message) ((void)0)
 34
 35#else // Not NO_REGISTER_GETTER_ASSERT.
 36
 37// This macro is called by the register code to check for runtime errors.
 38#define _GETTER_ASSERT_TRUE(expression, message)                                 \
 39  {                                                                              \
 40    if (!static_cast<bool>(expression)) {                                        \
 41      std::ostringstream diagnostics;                                            \
 42      diagnostics << "Got read value out of range in " << __FILE__ << ":"        \
 43                  << __LINE__ << ", message: " << message << ".";                \
 44      std::string diagnostic_message = diagnostics.str();                        \
 45      _assert_failed(&diagnostic_message);                                       \
 46    }                                                                            \
 47  }
 48
 49#endif // NO_REGISTER_GETTER_ASSERT.
 50
 51#ifdef NO_REGISTER_ARRAY_INDEX_ASSERT
 52
 53#define _ARRAY_INDEX_ASSERT_TRUE(expression, message) ((void)0)
 54
 55#else // Not NO_REGISTER_ARRAY_INDEX_ASSERT.
 56
 57// This macro is called by the register code to check for runtime errors.
 58#define _ARRAY_INDEX_ASSERT_TRUE(expression, message)                            \
 59  {                                                                              \
 60    if (!static_cast<bool>(expression)) {                                        \
 61      std::ostringstream diagnostics;                                            \
 62      diagnostics << "Provided array index out of range in " << __FILE__ << ":"  \
 63                  << __LINE__ << ", message: " << message << ".";                \
 64      std::string diagnostic_message = diagnostics.str();                        \
 65      _assert_failed(&diagnostic_message);                                       \
 66    }                                                                            \
 67  }
 68
 69#endif // NO_REGISTER_ARRAY_INDEX_ASSERT.
 70
 71  Caesar::Caesar(volatile uint8_t *base_address, bool (*assertion_handler) (const std::string*))
 72      : m_registers(reinterpret_cast<volatile uint32_t *>(base_address)),
 73        m_assertion_handler(assertion_handler)
 74  {
 75    // Empty
 76  }
 77
 78  void Caesar::_assert_failed(const std::string *message) const
 79  {
 80    m_assertion_handler(message);
 81  }
 82
 83  // ---------------------------------------------------------------------------
 84  // Methods for the 'config' register.
 85  // See interface header for documentation.
 86
 87  uint32_t Caesar::get_config() const
 88  {
 89    const size_t index = 0;
 90    const uint32_t result = m_registers[index];
 91
 92    return result;
 93  }
 94
 95  caesar::config::severity_level::Enumeration Caesar::get_config_severity_level() const
 96  {
 97    const uint32_t register_value = get_config();
 98    const caesar::config::severity_level::Enumeration field_value = get_config_severity_level_from_value(register_value);
 99
100    return field_value;
101  }
102
103  caesar::config::severity_level::Enumeration Caesar::get_config_severity_level_from_value(
104    uint32_t register_value
105  ) const
106  {
107    const uint32_t shift = 0uL;
108    const uint32_t mask_at_base = 0b11uL;
109    const uint32_t mask_shifted = mask_at_base << shift;
110
111    const uint32_t result_masked = register_value & mask_shifted;
112    const uint32_t result_shifted = result_masked >> shift;
113
114    caesar::config::severity_level::Enumeration field_value;
115
116    // "Cast" to the enum type.
117    field_value = caesar::config::severity_level::Enumeration(result_shifted);
118
119    return field_value;
120  }
121
122  caesar::config::packet_source::Enumeration Caesar::get_config_packet_source() const
123  {
124    const uint32_t register_value = get_config();
125    const caesar::config::packet_source::Enumeration field_value = get_config_packet_source_from_value(register_value);
126
127    return field_value;
128  }
129
130  caesar::config::packet_source::Enumeration Caesar::get_config_packet_source_from_value(
131    uint32_t register_value
132  ) const
133  {
134    const uint32_t shift = 2uL;
135    const uint32_t mask_at_base = 0b11uL;
136    const uint32_t mask_shifted = mask_at_base << shift;
137
138    const uint32_t result_masked = register_value & mask_shifted;
139    const uint32_t result_shifted = result_masked >> shift;
140
141    caesar::config::packet_source::Enumeration field_value;
142
143    // "Cast" to the enum type.
144    field_value = caesar::config::packet_source::Enumeration(result_shifted);
145
146    return field_value;
147  }
148
149  void Caesar::set_config(
150    uint32_t register_value
151  ) const
152  {
153    const size_t index = 0;
154    m_registers[index] = register_value;
155  }
156
157  void Caesar::set_config_severity_level(
158    caesar::config::severity_level::Enumeration field_value
159  ) const
160  {
161    // Get the current value of other fields by reading register on the bus.
162    const uint32_t current_register_value = get_config();
163    const uint32_t result_register_value = set_config_severity_level_from_value(current_register_value, field_value);
164    set_config(result_register_value);
165  }
166
167  uint32_t Caesar::set_config_severity_level_from_value(
168    uint32_t register_value,
169    caesar::config::severity_level::Enumeration field_value
170  ) const  {
171    const uint32_t shift = 0uL;
172    const uint32_t mask_at_base = 0b11uL;
173    const uint32_t mask_shifted = mask_at_base << shift;
174
175    const uint32_t field_value_masked = field_value & mask_at_base;
176    const uint32_t field_value_masked_and_shifted = field_value_masked << shift;
177
178    const uint32_t mask_shifted_inverse = ~mask_shifted;
179    const uint32_t register_value_masked = register_value & mask_shifted_inverse;
180
181    const uint32_t result_register_value = register_value_masked | field_value_masked_and_shifted;
182
183    return result_register_value;
184  }
185
186  void Caesar::set_config_packet_source(
187    caesar::config::packet_source::Enumeration field_value
188  ) const
189  {
190    // Get the current value of other fields by reading register on the bus.
191    const uint32_t current_register_value = get_config();
192    const uint32_t result_register_value = set_config_packet_source_from_value(current_register_value, field_value);
193    set_config(result_register_value);
194  }
195
196  uint32_t Caesar::set_config_packet_source_from_value(
197    uint32_t register_value,
198    caesar::config::packet_source::Enumeration field_value
199  ) const  {
200    const uint32_t shift = 2uL;
201    const uint32_t mask_at_base = 0b11uL;
202    const uint32_t mask_shifted = mask_at_base << shift;
203
204    const uint32_t field_value_masked = field_value & mask_at_base;
205    const uint32_t field_value_masked_and_shifted = field_value_masked << shift;
206
207    const uint32_t mask_shifted_inverse = ~mask_shifted;
208    const uint32_t register_value_masked = register_value & mask_shifted_inverse;
209
210    const uint32_t result_register_value = register_value_masked | field_value_masked_and_shifted;
211
212    return result_register_value;
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// This file is automatically generated by hdl-registers version 6.2.1-dev.
 2// Code generator CHeaderGenerator version 1.0.0.
 3// Generated 2024-12-19 20:52 at commit cd01ff93f646632c.
 4// Register hash c2412eacf08bbf54a4f274f2d5acaec28407a34e.
 5
 6#ifndef CAESAR_REGS_H
 7#define CAESAR_REGS_H
 8
 9
10// Number of registers within this register map.
11#define CAESAR_NUM_REGS (1u)
12
13// Type for this register map.
14typedef struct caesar_regs_t
15{
16  // Mode "Read, Write".
17  uint32_t config;
18} caesar_regs_t;
19
20// Address of the 'config' register.
21// Mode 'Read, Write'.
22#define CAESAR_CONFIG_INDEX (0u)
23#define CAESAR_CONFIG_ADDR (4u * CAESAR_CONFIG_INDEX)
24// Attributes for the 'severity_level' field in the 'config' register.
25#define CAESAR_CONFIG_SEVERITY_LEVEL_SHIFT (0u)
26#define CAESAR_CONFIG_SEVERITY_LEVEL_MASK (0b11u << 0u)
27#define CAESAR_CONFIG_SEVERITY_LEVEL_MASK_INVERSE (~CAESAR_CONFIG_SEVERITY_LEVEL_MASK)
28enum CaesarConfigSeverityLevel
29{
30  CAESAR_CONFIG_SEVERITY_LEVEL_INFO = 0,
31  CAESAR_CONFIG_SEVERITY_LEVEL_WARNING = 1,
32  CAESAR_CONFIG_SEVERITY_LEVEL_ERROR = 2,
33  CAESAR_CONFIG_SEVERITY_LEVEL_FAILURE = 3,
34};
35// Attributes for the 'packet_source' field in the 'config' register.
36#define CAESAR_CONFIG_PACKET_SOURCE_SHIFT (2u)
37#define CAESAR_CONFIG_PACKET_SOURCE_MASK (0b11u << 2u)
38#define CAESAR_CONFIG_PACKET_SOURCE_MASK_INVERSE (~CAESAR_CONFIG_PACKET_SOURCE_MASK)
39enum CaesarConfigPacketSource
40{
41  CAESAR_CONFIG_PACKET_SOURCE_STREAMING = 0,
42  CAESAR_CONFIG_PACKET_SOURCE_DMA = 1,
43  CAESAR_CONFIG_PACKET_SOURCE_NONE = 2,
44};
45
46#endif // CAESAR_REGS_H