Bit fields

Register fields can be of the type bit. Meaning a field of width one that can only take on the logic values of zero or one.

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

TOML that sets up a register with bit fields.
 1[conf]
 2
 3mode = "r_w"
 4description = "Configuration register."
 5
 6# This will allocate a bit field named "enable" in the "conf" register.
 7# The "type" property MUST be present and set to "bit".
 8enable.type = "bit"
 9
10# The "description" property is OPTIONAL for a bit field.
11# Will default to "" if not specified.
12# The value specified MUST be a string.
13enable.description = "Enable data passthrough."
14
15# The "default_value" property is OPTIONAL for a bit field.
16# Will default to "0" if not specified.
17# The value specified MUST be a string, consisting of either a "1" or a "0".
18enable.default_value = "1"
19
20
21invert.type = "bit"
22invert.description = "Optionally enable inversion of data."

Note that the second field does not have any default value specified, meaning it will default to 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 bit 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_bit.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_bit(
35        name="enable",
36        description="Enable data passthrough.",
37        default_value="1",
38    )
39
40    register.append_bit(
41        name="invert",
42        description="Optionally enable inversion of data.",
43        default_value="0",
44    )
45
46    return register_list
47
48
49def generate(register_list: RegisterList, output_folder: Path) -> None:
50    """
51    Generate the artifacts that we are interested in.
52    """
53    CHeaderGenerator(register_list=register_list, output_folder=output_folder).create()
54
55    CppImplementationGenerator(register_list=register_list, output_folder=output_folder).create()
56    CppInterfaceGenerator(register_list=register_list, output_folder=output_folder).create()
57
58    HtmlPageGenerator(register_list=register_list, output_folder=output_folder).create()
59
60    VhdlRegisterPackageGenerator(register_list=register_list, output_folder=output_folder).create()
61    VhdlRecordPackageGenerator(register_list=register_list, output_folder=output_folder).create()
62
63
64def main(output_folder: Path) -> None:
65    generate(register_list=parse_toml(), output_folder=output_folder / "toml")
66    generate(register_list=create_from_api(), output_folder=output_folder / "api")
67
68
69if __name__ == "__main__":
70    main(output_folder=Path(sys.argv[1]))

See Register.append_bit() and the Bit class for more Python API details.

Generated code

See below for a description of the code that can be generated when using bit 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 bit field is documented with its bit index, default value and description.

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. For each bit field there is a named constant that defines the bit’s index within the register.

  3. In VHDL, slicing out a bit from the register value will yield a value of type std_ulogic, meaning that typically no casting is needed. Hence there are no conversion functions for bit fields, the way there are for e.g. enumeration fields.

Click to expand/collapse code.
Generated VHDL register package.
 1-- -----------------------------------------------------------------------------
 2-- This file is automatically generated by hdl-registers version 7.3.1-dev.
 3-- Code generator VhdlRegisterPackageGenerator version 2.0.0.
 4-- Generated 2025-04-26 09:24 at Git commit e16bd7741c27.
 5-- Register hash 875f95ff1d46cbfb4a58f0314fa90bf2c0b5352a.
 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 'enable' field.
51  constant caesar_conf_enable : natural := 0;
52  -- Default value of the 'enable' field.
53  constant caesar_conf_enable_init : std_ulogic := '1';
54
55  -- Range of the 'invert' field.
56  constant caesar_conf_invert : natural := 1;
57  -- Default value of the 'invert' field.
58  constant caesar_conf_invert_init : std_ulogic := '0';
59
60end package;
61
62package body caesar_regs_pkg is
63
64  constant caesar_register_map : register_definition_vec_t(caesar_register_range) := (
65    0 => (index => caesar_conf, mode => r_w, utilized_width => 2)
66  );
67
68  constant caesar_regs_init : caesar_regs_t := (
69    0 => "00000000000000000000000000000001"
70  );
71
72end 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 bits set up in our example: enable and invert.

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

result_valid <= input_valid and regs_down.config.enable;
Click to expand/collapse code.
Generated VHDL record package.
  1-- -----------------------------------------------------------------------------
  2-- This file is automatically generated by hdl-registers version 7.3.1-dev.
  3-- Code generator VhdlRecordPackageGenerator version 1.0.0.
  4-- Generated 2025-04-26 09:24 at Git commit e16bd7741c27.
  5-- Register hash 875f95ff1d46cbfb4a58f0314fa90bf2c0b5352a.
  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    enable : std_ulogic;
 26    invert : std_ulogic;
 27  end record;
 28  -- Default value for the 'conf' register as a record.
 29  constant caesar_conf_init : caesar_conf_t := (
 30    enable => caesar_conf_enable_init,
 31    invert => caesar_conf_invert_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_enable) := data.enable;
 92    result(caesar_conf_invert) := data.invert;
 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.enable := data(caesar_conf_enable);
101    result.invert := data(caesar_conf_invert);
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

Note the setters and getters for each individual field value.

Click to expand/collapse code.
Generated C++ class interface code.
  1// -----------------------------------------------------------------------------
  2// This file is automatically generated by hdl-registers version 7.3.1-dev.
  3// Code generator CppInterfaceGenerator version 1.0.0.
  4// Generated 2025-04-26 09:24 at Git commit e16bd7741c27.
  5// Register hash 875f95ff1d46cbfb4a58f0314fa90bf2c0b5352a.
  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 'enable' field.
 23      namespace enable
 24      {
 25        // The number of bits that the field occupies.
 26        static const size_t width = 1;
 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        // Initial value of the field at device startup/reset.
 35        static const bool default_value = true;
 36        // Raw representation of the initial value, at the the field's bit index.
 37        static const uint32_t default_value_raw = 1 << shift;
 38      }
 39
 40      // Attributes for the 'invert' field.
 41      namespace invert
 42      {
 43        // The number of bits that the field occupies.
 44        static const size_t width = 1;
 45        // The bit index of the lowest bit in the field.
 46        static const size_t shift = 1;
 47        // The bit mask of the field, at index zero.
 48        static const uint32_t mask_at_base = (1uLL << width) - 1;
 49        // The bit mask of the field, at the field's bit index.
 50        static const uint32_t mask_shifted = mask_at_base << shift;
 51
 52        // Initial value of the field at device startup/reset.
 53        static const bool default_value = false;
 54        // Raw representation of the initial value, at the the field's bit index.
 55        static const uint32_t default_value_raw = 0 << shift;
 56      }
 57
 58      // Struct that holds the value of each field in the register,
 59      // in a native C++ representation.
 60      struct Value {
 61        bool enable;
 62        bool invert;
 63      };
 64      // Initial value of the register at device startup/reset.
 65      const Value default_value = {
 66        enable::default_value,
 67        invert::default_value,
 68      };
 69    }
 70
 71  } // namespace caesar
 72
 73  class ICaesar
 74  {
 75  public:
 76    // Number of registers within this register list.
 77    static const size_t num_registers = 1uL;
 78
 79    virtual ~ICaesar() {}
 80
 81    // -------------------------------------------------------------------------
 82    // Methods for the 'conf' register.
 83    // Mode 'Read, Write'.
 84    // -------------------------------------------------------------------------
 85    // Read the whole register value over the register bus.
 86    virtual caesar::conf::Value get_conf() const = 0;
 87
 88    // Read the whole register value over the register bus.
 89    // This method returns the raw register value without any type conversion.
 90    virtual uint32_t get_conf_raw() const = 0;
 91
 92    // Read the register and slice out the 'enable' field value.
 93    virtual bool get_conf_enable() const = 0;
 94
 95    // Read the register and slice out the 'invert' field value.
 96    virtual bool get_conf_invert() const = 0;
 97
 98    // Write the whole register value over the register bus.
 99    virtual void set_conf(
100      caesar::conf::Value register_value
101    ) const = 0;
102
103    // Write the whole register value over the register bus.
104    // This method takes a raw register value and does not perform any type conversion.
105    virtual void set_conf_raw(
106      uint32_t register_value
107    ) const = 0;
108
109    // Write the 'enable' field value.
110    // Will read-modify-write the register.
111    virtual void set_conf_enable(
112      bool field_value
113    ) const = 0;
114
115    // Write the 'invert' field value.
116    // Will read-modify-write the register.
117    virtual void set_conf_invert(
118      bool field_value
119    ) const = 0;
120    // -------------------------------------------------------------------------
121  };
122
123} // namespace fpga_regs

C++ implementation

Click to expand/collapse code.
Generated C++ class implementation code.
  1// -----------------------------------------------------------------------------
  2// This file is automatically generated by hdl-registers version 7.3.1-dev.
  3// Code generator CppImplementationGenerator version 2.0.2.
  4// Generated 2025-04-26 09:24 at Git commit e16bd7741c27.
  5// Register hash 875f95ff1d46cbfb4a58f0314fa90bf2c0b5352a.
  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 << "caesar.cpp:" << __LINE__                                   \
 25                  << ": " << 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 << "caesar.cpp:" << __LINE__                                   \
 45                  << ": " << 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 << "caesar.cpp:" << __LINE__                                   \
 65                  << ": " << 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 'conf' register.
 82  // Mode 'Read, Write'.
 83  // ---------------------------------------------------------------------------
 84  // Read the whole register value over the register bus.
 85  caesar::conf::Value Caesar::get_conf() const
 86  {
 87    const uint32_t raw_value = get_conf_raw();
 88
 89    const bool enable_value = get_conf_enable_from_raw(raw_value);
 90    const bool invert_value = get_conf_invert_from_raw(raw_value);
 91
 92    return {enable_value, invert_value};
 93  }
 94
 95  // Read the whole register value over the register bus.
 96  // This method returns the raw register value without any type conversion.
 97  uint32_t Caesar::get_conf_raw() const
 98  {
 99    const size_t index = 0;
100    const uint32_t raw_value = m_registers[index];
101
102    return raw_value;
103  }
104
105  // Read the register and slice out the 'enable' field value.
106  bool Caesar::get_conf_enable() const
107  {
108    const uint32_t raw_value = get_conf_raw();
109
110    return get_conf_enable_from_raw(raw_value);
111  }
112
113  // Slice out the 'enable' field value from a given raw register value.
114  // Performs no operation on the register bus.
115  bool Caesar::get_conf_enable_from_raw(
116    uint32_t register_value
117  ) const
118  {
119    const uint32_t result_masked = register_value & caesar::conf::enable::mask_shifted;
120    const uint32_t result_shifted = result_masked >> caesar::conf::enable::shift;
121
122    // Convert to the result type.
123    const bool field_value = static_cast<bool>(result_shifted);
124
125    return field_value;
126  }
127
128  // Read the register and slice out the 'invert' field value.
129  bool Caesar::get_conf_invert() const
130  {
131    const uint32_t raw_value = get_conf_raw();
132
133    return get_conf_invert_from_raw(raw_value);
134  }
135
136  // Slice out the 'invert' field value from a given raw register value.
137  // Performs no operation on the register bus.
138  bool Caesar::get_conf_invert_from_raw(
139    uint32_t register_value
140  ) const
141  {
142    const uint32_t result_masked = register_value & caesar::conf::invert::mask_shifted;
143    const uint32_t result_shifted = result_masked >> caesar::conf::invert::shift;
144
145    // Convert to the result type.
146    const bool field_value = static_cast<bool>(result_shifted);
147
148    return field_value;
149  }
150
151  // Write the whole register value over the register bus.
152  void Caesar::set_conf(
153    caesar::conf::Value register_value
154  ) const
155  {
156    const uint32_t enable_value = get_conf_enable_to_raw(register_value.enable);
157    const uint32_t invert_value = get_conf_invert_to_raw(register_value.invert);
158    const uint32_t raw_value = enable_value | invert_value;
159
160    set_conf_raw(raw_value);
161  }
162
163  // Write the whole register value over the register bus.
164  // This method takes a raw register value and does not perform any type conversion.
165  void Caesar::set_conf_raw(
166    uint32_t register_value
167  ) const
168  {
169    const size_t index = 0;
170    m_registers[index] = register_value;
171  }
172
173  // Write the 'enable' field value.
174  // Will read-modify-write the register.
175  void Caesar::set_conf_enable(
176    bool field_value
177  ) const
178  {
179    const size_t index = 0;
180
181    const uint32_t raw_value = m_registers[index];
182    const uint32_t mask_shifted_inverse = ~caesar::conf::enable::mask_shifted;
183    const uint32_t base_value = raw_value & mask_shifted_inverse;
184
185    const uint32_t field_value_raw = get_conf_enable_to_raw(field_value);
186    const uint32_t register_value = base_value | field_value_raw;
187
188    m_registers[index] = register_value;
189  }
190
191  // Get the raw representation of a given 'enable' field value.
192  // Performs no operation on the register bus.
193  uint32_t Caesar::get_conf_enable_to_raw(bool field_value) const
194  {
195    const uint32_t field_value_casted = static_cast<uint32_t>(field_value);
196    const uint32_t field_value_shifted = field_value_casted << caesar::conf::enable::shift;
197
198    return field_value_shifted;
199  }
200
201  // Write the 'invert' field value.
202  // Will read-modify-write the register.
203  void Caesar::set_conf_invert(
204    bool field_value
205  ) const
206  {
207    const size_t index = 0;
208
209    const uint32_t raw_value = m_registers[index];
210    const uint32_t mask_shifted_inverse = ~caesar::conf::invert::mask_shifted;
211    const uint32_t base_value = raw_value & mask_shifted_inverse;
212
213    const uint32_t field_value_raw = get_conf_invert_to_raw(field_value);
214    const uint32_t register_value = base_value | field_value_raw;
215
216    m_registers[index] = register_value;
217  }
218
219  // Get the raw representation of a given 'invert' field value.
220  // Performs no operation on the register bus.
221  uint32_t Caesar::get_conf_invert_to_raw(bool field_value) const
222  {
223    const uint32_t field_value_casted = static_cast<uint32_t>(field_value);
224    const uint32_t field_value_shifted = field_value_casted << caesar::conf::invert::shift;
225
226    return field_value_shifted;
227  }
228  // ---------------------------------------------------------------------------
229
230} // namespace fpga_regs

C header

The C code below is produced by the generate() call in the Python example above. The index and mask of 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.3.1-dev.
 3// Code generator CHeaderGenerator version 1.0.0.
 4// Generated 2025-04-26 09:24 at Git commit e16bd7741c27.
 5// Register hash 875f95ff1d46cbfb4a58f0314fa90bf2c0b5352a.
 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 'enable' field in the 'conf' register.
27#define CAESAR_CONF_ENABLE_SHIFT (0u)
28#define CAESAR_CONF_ENABLE_MASK (0b1u << 0u)
29#define CAESAR_CONF_ENABLE_MASK_INVERSE (~CAESAR_CONF_ENABLE_MASK)
30// Attributes for the 'invert' field in the 'conf' register.
31#define CAESAR_CONF_INVERT_SHIFT (1u)
32#define CAESAR_CONF_INVERT_MASK (0b1u << 1u)
33#define CAESAR_CONF_INVERT_MASK_INVERSE (~CAESAR_CONF_INVERT_MASK)
34
35#endif // CAESAR_REGS_H