Bit vector fields

Register fields can be of the type bit vector. Meaning, an array of logic bits.

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

TOML that sets up a register with bit vector fields.
 1[conf]
 2
 3mode = "r_w"
 4description = "Configuration register."
 5
 6# This will allocate a bit vector field named "tuser" in the "conf" register.
 7# The "type" property MUST be present and set to "bit_vector".
 8tuser.type = "bit_vector"
 9
10# The "width" property MUST be present for a bit vector field.
11# The value specified MUST be a positive integer.
12tuser.width = 4
13
14# The "description" property is OPTIONAL for a bit vector field.
15# Will default to "" if not specified.
16# The value specified MUST be a string.
17tuser.description = "Value to set for **TUSER** in the data stream."
18
19# The "default_value" property is OPTIONAL for a bit vector field.
20# Will default to all zeros if not specified.
21# The value specified MUST be either
22# 1. A string of 1's and 0's. The string length MUST be the same as the field width.
23# 2. An unsigned integer. The value's binary representation MUST fit within the field width.
24tuser.default_value = "0101"
25
26
27tid.type = "bit_vector"
28tid.width = 8
29tid.description = "Value to set for **TID** in the data stream."
30tid.default_value = 0xf3
31
32
33tdest.type = "bit_vector"
34tdest.width = 3
35tdest.description = "Value to set for **TDEST** in the data stream."

Note that the third field does not have any default value specified, meaning it will default to all zeros.

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 vector 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_vector.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_vector(
35        name="tuser",
36        description="Value to set for **TUSER** in the data stream.",
37        width=4,
38        default_value="0101",
39    )
40
41    register.append_bit_vector(
42        name="tid",
43        description="Value to set for **TID** in the data stream.",
44        width=8,
45        default_value=0xF3,
46    )
47
48    register.append_bit_vector(
49        name="tdest",
50        description="Value to set for **TDEST** in the data stream.",
51        width=3,
52        default_value=0,
53    )
54
55    return register_list
56
57
58def generate(register_list: RegisterList, output_folder: Path) -> None:
59    """
60    Generate the artifacts that we are interested in.
61    """
62    CHeaderGenerator(register_list=register_list, output_folder=output_folder).create()
63
64    CppImplementationGenerator(register_list=register_list, output_folder=output_folder).create()
65    CppInterfaceGenerator(register_list=register_list, output_folder=output_folder).create()
66
67    HtmlPageGenerator(register_list=register_list, output_folder=output_folder).create()
68
69    VhdlRegisterPackageGenerator(register_list=register_list, output_folder=output_folder).create()
70    VhdlRecordPackageGenerator(register_list=register_list, output_folder=output_folder).create()
71
72
73def main(output_folder: Path) -> None:
74    generate(register_list=parse_toml(), output_folder=output_folder / "toml")
75    generate(register_list=create_from_api(), output_folder=output_folder / "api")
76
77
78if __name__ == "__main__":
79    main(output_folder=Path(sys.argv[1]))

See Register.append_bit_vector() and the BitVector class for more Python API details.

Generated code

See below for a description of the code that can be generated when using bit vector 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 vector field is documented with its range, 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. The first field is four bits wide, occupying bits 3 down to 0, while the second one is eight bits wide, occupying but 11 down to 4.

  3. For each bit vector field there is a named integer subtype that defines the fields’s bit range within the register.

  4. In VHDL, slicing out a range from the register value will yield a value of type std_ulogic_vector, meaning that typically no casting is needed. Hence there are no conversion functions for bit vector 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 8.0.1-dev.
 3-- Code generator VhdlRegisterPackageGenerator version 2.0.0.
 4-- Generated 2025-05-08 20:52 at Git commit f53f19ab11e0.
 5-- Register hash d4bbf353ec4cd79009cabb4c3f23dbd4cce80525.
 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 'tuser' field.
51  subtype caesar_conf_tuser is natural range 3 downto 0;
52  -- Width of the 'tuser' field.
53  constant caesar_conf_tuser_width : positive := 4;
54  -- Type for the 'tuser' field.
55  subtype caesar_conf_tuser_t is u_unsigned(3 downto 0);
56  -- Default value of the 'tuser' field.
57  constant caesar_conf_tuser_init : caesar_conf_tuser_t := "0101";
58
59  -- Range of the 'tid' field.
60  subtype caesar_conf_tid is natural range 11 downto 4;
61  -- Width of the 'tid' field.
62  constant caesar_conf_tid_width : positive := 8;
63  -- Type for the 'tid' field.
64  subtype caesar_conf_tid_t is u_unsigned(7 downto 0);
65  -- Default value of the 'tid' field.
66  constant caesar_conf_tid_init : caesar_conf_tid_t := "11110011";
67
68  -- Range of the 'tdest' field.
69  subtype caesar_conf_tdest is natural range 14 downto 12;
70  -- Width of the 'tdest' field.
71  constant caesar_conf_tdest_width : positive := 3;
72  -- Type for the 'tdest' field.
73  subtype caesar_conf_tdest_t is u_unsigned(2 downto 0);
74  -- Default value of the 'tdest' field.
75  constant caesar_conf_tdest_init : caesar_conf_tdest_t := "000";
76
77end package;
78
79package body caesar_regs_pkg is
80
81  constant caesar_register_map : register_definition_vec_t(caesar_register_range) := (
82    0 => (index => caesar_conf, mode => r_w, utilized_width => 15)
83  );
84
85  constant caesar_regs_init : caesar_regs_t := (
86    0 => "00000000000000000000111100110101"
87  );
88
89end 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 bit vectors set up in our example: tuser and tid. These are of unsigned vector types defined in the base register package above.

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

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

C++

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

The class header is skipped here, since its inclusion would make this page very long. See C++ 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 8.0.1-dev.
  3// Code generator CppInterfaceGenerator version 1.0.0.
  4// Generated 2025-05-08 20:52 at Git commit f53f19ab11e0.
  5// Register hash d4bbf353ec4cd79009cabb4c3f23dbd4cce80525.
  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 'tuser' field.
 23      namespace tuser
 24      {
 25        // The number of bits that the field occupies.
 26        static const size_t width = 4;
 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 uint32_t default_value = 5;
 36        // Raw representation of the initial value, at the the field's bit index.
 37        static const uint32_t default_value_raw = 0b0101uL << shift;
 38      }
 39
 40      // Attributes for the 'tid' field.
 41      namespace tid
 42      {
 43        // The number of bits that the field occupies.
 44        static const size_t width = 8;
 45        // The bit index of the lowest bit in the field.
 46        static const size_t shift = 4;
 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 uint32_t default_value = 243;
 54        // Raw representation of the initial value, at the the field's bit index.
 55        static const uint32_t default_value_raw = 0b11110011uL << shift;
 56      }
 57
 58      // Attributes for the 'tdest' field.
 59      namespace tdest
 60      {
 61        // The number of bits that the field occupies.
 62        static const size_t width = 3;
 63        // The bit index of the lowest bit in the field.
 64        static const size_t shift = 12;
 65        // The bit mask of the field, at index zero.
 66        static const uint32_t mask_at_base = (1uLL << width) - 1;
 67        // The bit mask of the field, at the field's bit index.
 68        static const uint32_t mask_shifted = mask_at_base << shift;
 69
 70        // Initial value of the field at device startup/reset.
 71        static const uint32_t default_value = 0;
 72        // Raw representation of the initial value, at the the field's bit index.
 73        static const uint32_t default_value_raw = 0b000uL << shift;
 74      }
 75
 76      // Struct that holds the value of each field in the register,
 77      // in a native C++ representation.
 78      struct Value {
 79        uint32_t tuser;
 80        uint32_t tid;
 81        uint32_t tdest;
 82      };
 83      // Initial value of the register at device startup/reset.
 84      const Value default_value = {
 85        tuser::default_value,
 86        tid::default_value,
 87        tdest::default_value,
 88      };
 89    }
 90
 91  } // namespace caesar
 92
 93  class ICaesar
 94  {
 95  public:
 96    // Number of registers within this register list.
 97    static const size_t num_registers = 1uL;
 98
 99    virtual ~ICaesar() {}
100
101    // -------------------------------------------------------------------------
102    // Methods for the 'conf' register.
103    // Mode 'Read, Write'.
104    // -------------------------------------------------------------------------
105    // Read the whole register value over the register bus.
106    virtual caesar::conf::Value get_conf() const = 0;
107
108    // Read the whole register value over the register bus.
109    // This method returns the raw register value without any type conversion.
110    virtual uint32_t get_conf_raw() const = 0;
111
112    // Read the register and slice out the 'tuser' field value.
113    virtual uint32_t get_conf_tuser() const = 0;
114
115    // Read the register and slice out the 'tid' field value.
116    virtual uint32_t get_conf_tid() const = 0;
117
118    // Read the register and slice out the 'tdest' field value.
119    virtual uint32_t get_conf_tdest() const = 0;
120
121    // Write the whole register value over the register bus.
122    virtual void set_conf(
123      caesar::conf::Value register_value
124    ) const = 0;
125
126    // Write the whole register value over the register bus.
127    // This method takes a raw register value and does not perform any type conversion.
128    virtual void set_conf_raw(
129      uint32_t register_value
130    ) const = 0;
131
132    // Write the 'tuser' field value.
133    // Will read-modify-write the register.
134    virtual void set_conf_tuser(
135      uint32_t field_value
136    ) const = 0;
137
138    // Write the 'tid' field value.
139    // Will read-modify-write the register.
140    virtual void set_conf_tid(
141      uint32_t field_value
142    ) const = 0;
143
144    // Write the 'tdest' field value.
145    // Will read-modify-write the register.
146    virtual void set_conf_tdest(
147      uint32_t field_value
148    ) const = 0;
149    // -------------------------------------------------------------------------
150  };
151
152} // namespace fpga_regs

C++ implementation

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

Click to expand/collapse code.
Generated C++ class implementation code.
  1// -----------------------------------------------------------------------------
  2// This file is automatically generated by hdl-registers version 8.0.1-dev.
  3// Code generator CppImplementationGenerator version 2.0.2.
  4// Generated 2025-05-08 20:52 at Git commit f53f19ab11e0.
  5// Register hash d4bbf353ec4cd79009cabb4c3f23dbd4cce80525.
  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 uint32_t tuser_value = get_conf_tuser_from_raw(raw_value);
 90    const uint32_t tid_value = get_conf_tid_from_raw(raw_value);
 91    const uint32_t tdest_value = get_conf_tdest_from_raw(raw_value);
 92
 93    return {tuser_value, tid_value, tdest_value};
 94  }
 95
 96  // Read the whole register value over the register bus.
 97  // This method returns the raw register value without any type conversion.
 98  uint32_t Caesar::get_conf_raw() const
 99  {
100    const size_t index = 0;
101    const uint32_t raw_value = m_registers[index];
102
103    return raw_value;
104  }
105
106  // Read the register and slice out the 'tuser' field value.
107  uint32_t Caesar::get_conf_tuser() const
108  {
109    const uint32_t raw_value = get_conf_raw();
110
111    return get_conf_tuser_from_raw(raw_value);
112  }
113
114  // Slice out the 'tuser' field value from a given raw register value.
115  // Performs no operation on the register bus.
116  uint32_t Caesar::get_conf_tuser_from_raw(
117    uint32_t register_value
118  ) const
119  {
120    const uint32_t result_masked = register_value & caesar::conf::tuser::mask_shifted;
121    const uint32_t result_shifted = result_masked >> caesar::conf::tuser::shift;
122
123    // No casting needed.
124    const uint32_t field_value = result_shifted;
125
126    return field_value;
127  }
128
129  // Read the register and slice out the 'tid' field value.
130  uint32_t Caesar::get_conf_tid() const
131  {
132    const uint32_t raw_value = get_conf_raw();
133
134    return get_conf_tid_from_raw(raw_value);
135  }
136
137  // Slice out the 'tid' field value from a given raw register value.
138  // Performs no operation on the register bus.
139  uint32_t Caesar::get_conf_tid_from_raw(
140    uint32_t register_value
141  ) const
142  {
143    const uint32_t result_masked = register_value & caesar::conf::tid::mask_shifted;
144    const uint32_t result_shifted = result_masked >> caesar::conf::tid::shift;
145
146    // No casting needed.
147    const uint32_t field_value = result_shifted;
148
149    return field_value;
150  }
151
152  // Read the register and slice out the 'tdest' field value.
153  uint32_t Caesar::get_conf_tdest() const
154  {
155    const uint32_t raw_value = get_conf_raw();
156
157    return get_conf_tdest_from_raw(raw_value);
158  }
159
160  // Slice out the 'tdest' field value from a given raw register value.
161  // Performs no operation on the register bus.
162  uint32_t Caesar::get_conf_tdest_from_raw(
163    uint32_t register_value
164  ) const
165  {
166    const uint32_t result_masked = register_value & caesar::conf::tdest::mask_shifted;
167    const uint32_t result_shifted = result_masked >> caesar::conf::tdest::shift;
168
169    // No casting needed.
170    const uint32_t field_value = result_shifted;
171
172    return field_value;
173  }
174
175  // Write the whole register value over the register bus.
176  void Caesar::set_conf(
177    caesar::conf::Value register_value
178  ) const
179  {
180    const uint32_t tuser_value = get_conf_tuser_to_raw(register_value.tuser);
181    const uint32_t tid_value = get_conf_tid_to_raw(register_value.tid);
182    const uint32_t tdest_value = get_conf_tdest_to_raw(register_value.tdest);
183    const uint32_t raw_value = tuser_value | tid_value | tdest_value;
184
185    set_conf_raw(raw_value);
186  }
187
188  // Write the whole register value over the register bus.
189  // This method takes a raw register value and does not perform any type conversion.
190  void Caesar::set_conf_raw(
191    uint32_t register_value
192  ) const
193  {
194    const size_t index = 0;
195    m_registers[index] = register_value;
196  }
197
198  // Write the 'tuser' field value.
199  // Will read-modify-write the register.
200  void Caesar::set_conf_tuser(
201    uint32_t field_value
202  ) const
203  {
204    const size_t index = 0;
205
206    const uint32_t raw_value = m_registers[index];
207    const uint32_t mask_shifted_inverse = ~caesar::conf::tuser::mask_shifted;
208    const uint32_t base_value = raw_value & mask_shifted_inverse;
209
210    const uint32_t field_value_raw = get_conf_tuser_to_raw(field_value);
211    const uint32_t register_value = base_value | field_value_raw;
212
213    m_registers[index] = register_value;
214  }
215
216  // Get the raw representation of a given 'tuser' field value.
217  // Performs no operation on the register bus.
218  uint32_t Caesar::get_conf_tuser_to_raw(uint32_t field_value) const
219  {
220    _SETTER_ASSERT_TRUE(
221      field_value <= 15,
222      "Got 'tuser' value out of range: " << field_value
223    );
224
225    const uint32_t field_value_shifted = field_value << caesar::conf::tuser::shift;
226
227    return field_value_shifted;
228  }
229
230  // Write the 'tid' field value.
231  // Will read-modify-write the register.
232  void Caesar::set_conf_tid(
233    uint32_t field_value
234  ) const
235  {
236    const size_t index = 0;
237
238    const uint32_t raw_value = m_registers[index];
239    const uint32_t mask_shifted_inverse = ~caesar::conf::tid::mask_shifted;
240    const uint32_t base_value = raw_value & mask_shifted_inverse;
241
242    const uint32_t field_value_raw = get_conf_tid_to_raw(field_value);
243    const uint32_t register_value = base_value | field_value_raw;
244
245    m_registers[index] = register_value;
246  }
247
248  // Get the raw representation of a given 'tid' field value.
249  // Performs no operation on the register bus.
250  uint32_t Caesar::get_conf_tid_to_raw(uint32_t field_value) const
251  {
252    _SETTER_ASSERT_TRUE(
253      field_value <= 255,
254      "Got 'tid' value out of range: " << field_value
255    );
256
257    const uint32_t field_value_shifted = field_value << caesar::conf::tid::shift;
258
259    return field_value_shifted;
260  }
261
262  // Write the 'tdest' field value.
263  // Will read-modify-write the register.
264  void Caesar::set_conf_tdest(
265    uint32_t field_value
266  ) const
267  {
268    const size_t index = 0;
269
270    const uint32_t raw_value = m_registers[index];
271    const uint32_t mask_shifted_inverse = ~caesar::conf::tdest::mask_shifted;
272    const uint32_t base_value = raw_value & mask_shifted_inverse;
273
274    const uint32_t field_value_raw = get_conf_tdest_to_raw(field_value);
275    const uint32_t register_value = base_value | field_value_raw;
276
277    m_registers[index] = register_value;
278  }
279
280  // Get the raw representation of a given 'tdest' field value.
281  // Performs no operation on the register bus.
282  uint32_t Caesar::get_conf_tdest_to_raw(uint32_t field_value) const
283  {
284    _SETTER_ASSERT_TRUE(
285      field_value <= 7,
286      "Got 'tdest' value out of range: " << field_value
287    );
288
289    const uint32_t field_value_shifted = field_value << caesar::conf::tdest::shift;
290
291    return field_value_shifted;
292  }
293  // ---------------------------------------------------------------------------
294
295} // namespace fpga_regs

C header

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

Click to expand/collapse code.
Generated C code.
 1// -----------------------------------------------------------------------------
 2// This file is automatically generated by hdl-registers version 8.0.1-dev.
 3// Code generator CHeaderGenerator version 1.0.0.
 4// Generated 2025-05-08 20:52 at Git commit f53f19ab11e0.
 5// Register hash d4bbf353ec4cd79009cabb4c3f23dbd4cce80525.
 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 'tuser' field in the 'conf' register.
27#define CAESAR_CONF_TUSER_SHIFT (0u)
28#define CAESAR_CONF_TUSER_MASK (0b1111u << 0u)
29#define CAESAR_CONF_TUSER_MASK_INVERSE (~CAESAR_CONF_TUSER_MASK)
30// Attributes for the 'tid' field in the 'conf' register.
31#define CAESAR_CONF_TID_SHIFT (4u)
32#define CAESAR_CONF_TID_MASK (0b11111111u << 4u)
33#define CAESAR_CONF_TID_MASK_INVERSE (~CAESAR_CONF_TID_MASK)
34// Attributes for the 'tdest' field in the 'conf' register.
35#define CAESAR_CONF_TDEST_SHIFT (12u)
36#define CAESAR_CONF_TDEST_MASK (0b111u << 12u)
37#define CAESAR_CONF_TDEST_MASK_INVERSE (~CAESAR_CONF_TDEST_MASK)
38
39#endif // CAESAR_REGS_H