Integer fields

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

This page will show you how the set up integer fields in a register, and will showcase all the code that can be generated from it.

Usage in TOML

The TOML file below shows how to set up a register with three integer fields. See comments for rules about the different properties.

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

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

Below you will see how you can parse this TOML file and generate artifacts from it.

Usage with Python API

The Python code below shows

  1. How to parse the TOML file listed above.

  2. How to create an identical register list when instead using the Python API.

  3. How to generate register artifacts.

Note that the result of the create_from_api call is identical to that of the parse_toml call. Meaning that using a TOML file or using the Python API is completely equivalent. You choose yourself which method you want to use in your code base.

Python code that sets up a register with integer fields.
 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
14
15THIS_DIR = Path(__file__).parent
16
17
18def parse_toml() -> RegisterList:
19    """
20    Create the register list by parsing a TOML data file.
21    """
22    return from_toml(name="caesar", toml_file=THIS_DIR.parent / "toml" / "field_integer.toml")
23
24
25def create_from_api() -> RegisterList:
26    """
27    Alternative method: Create the register list by using the Python API.
28    """
29    register_list = RegisterList(name="caesar")
30
31    register = register_list.append_register(
32        name="config", mode="r_w", description="Configuration register."
33    )
34
35    register.append_integer(
36        name="burst_length_bytes",
37        description="The number of bytes to request.",
38        min_value=1,
39        max_value=256,
40        default_value=64,
41    )
42
43    register.append_integer(
44        name="increment",
45        description="Offset that will be added to data.",
46        min_value=-4,
47        max_value=3,
48        default_value=0,
49    )
50
51    register.append_integer(
52        name="retry_count",
53        description="Number of retry attempts before giving up.",
54        min_value=0,
55        max_value=5,
56        default_value=0,
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_integer() for more Python API details.

Generated code

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

HTML page

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

See HTML code generator for more details about the HTML generator and its capabilities.

HTML page

VHDL package

The VHDL code below is produced by the generate() call in the Python example above. Click the button to expand and view the code. See VHDL code generator for instructions on how it can be used in your VHDL project.

Base register package

Some interesting things to notice:

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

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

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

    1. Converting from the integer type to std_logic_vector.

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

Click to expand/collapse code.
Generated VHDL register package. :language: VHDL :linenos:
-- This file is automatically generated by hdl-registers version 5.1.4-dev.
-- Code generator VhdlRegisterPackageGenerator version 1.0.0.
-- Generated 2024-04-26 20:51 at commit 2c446088490c1e41.
-- Register hash 5bf25bc5ce7e7bb89d3f05d6ed90c19998888575.

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.fixed_pkg.all;

library reg_file;
use reg_file.reg_file_pkg.all;


package caesar_regs_pkg is

  -- ---------------------------------------------------------------------------
  -- The valid range of register indexes.
  subtype caesar_reg_range is natural range 0 to 0;

  -- Register indexes, within the list of registers.
  constant caesar_config : natural := 0;

  -- Declare 'reg_map' and 'regs_init' constants here but define them in body (deferred constants).
  -- So that functions have been elaborated when they are called.
  -- Needed for ModelSim compilation to pass.

  -- To be used as the 'regs' generic of 'axi_lite_reg_file.vhd'.
  constant caesar_reg_map : reg_definition_vec_t(caesar_reg_range);

  -- To be used for the 'regs_up' and 'regs_down' ports of 'axi_lite_reg_file.vhd'.
  subtype caesar_regs_t is reg_vec_t(caesar_reg_range);
  -- To be used as the 'default_values' generic of 'axi_lite_reg_file.vhd'.
  constant caesar_regs_init : caesar_regs_t;

  -- To be used for the 'reg_was_read' and 'reg_was_written' ports of 'axi_lite_reg_file.vhd'.
  subtype caesar_reg_was_accessed_t is std_ulogic_vector(caesar_reg_range);

  -- -----------------------------------------------------------------------------
  -- Fields in the 'config' register.
  -- Range of the 'burst_length_bytes' field.
  subtype caesar_config_burst_length_bytes is natural range 8 downto 0;
  -- Width of the 'burst_length_bytes' field.
  constant caesar_config_burst_length_bytes_width : positive := 9;
  -- Type for the 'burst_length_bytes' field.
  subtype caesar_config_burst_length_bytes_t is integer range 1 to 256;
  -- Default value of the 'burst_length_bytes' field.
  constant caesar_config_burst_length_bytes_init : caesar_config_burst_length_bytes_t := 64;
  -- Type for the 'burst_length_bytes' field as an SLV.
  subtype caesar_config_burst_length_bytes_slv_t is std_ulogic_vector(8 downto 0);
  -- Cast a 'burst_length_bytes' field value to SLV.
  function to_caesar_config_burst_length_bytes_slv(data : caesar_config_burst_length_bytes_t) return caesar_config_burst_length_bytes_slv_t;
  -- Get a 'burst_length_bytes' field value from a register value.
  function to_caesar_config_burst_length_bytes(data : reg_t) return caesar_config_burst_length_bytes_t;

  -- Range of the 'increment' field.
  subtype caesar_config_increment is natural range 11 downto 9;
  -- Width of the 'increment' field.
  constant caesar_config_increment_width : positive := 3;
  -- Type for the 'increment' field.
  subtype caesar_config_increment_t is integer range -4 to 3;
  -- Default value of the 'increment' field.
  constant caesar_config_increment_init : caesar_config_increment_t := 0;
  -- Type for the 'increment' field as an SLV.
  subtype caesar_config_increment_slv_t is std_ulogic_vector(2 downto 0);
  -- Cast a 'increment' field value to SLV.
  function to_caesar_config_increment_slv(data : caesar_config_increment_t) return caesar_config_increment_slv_t;
  -- Get a 'increment' field value from a register value.
  function to_caesar_config_increment(data : reg_t) return caesar_config_increment_t;

  -- Range of the 'retry_count' field.
  subtype caesar_config_retry_count is natural range 14 downto 12;
  -- Width of the 'retry_count' field.
  constant caesar_config_retry_count_width : positive := 3;
  -- Type for the 'retry_count' field.
  subtype caesar_config_retry_count_t is integer range 0 to 5;
  -- Default value of the 'retry_count' field.
  constant caesar_config_retry_count_init : caesar_config_retry_count_t := 0;
  -- Type for the 'retry_count' field as an SLV.
  subtype caesar_config_retry_count_slv_t is std_ulogic_vector(2 downto 0);
  -- Cast a 'retry_count' field value to SLV.
  function to_caesar_config_retry_count_slv(data : caesar_config_retry_count_t) return caesar_config_retry_count_slv_t;
  -- Get a 'retry_count' field value from a register value.
  function to_caesar_config_retry_count(data : reg_t) return caesar_config_retry_count_t;

end package;

package body caesar_regs_pkg is

  constant caesar_reg_map : reg_definition_vec_t(caesar_reg_range) := (
    0 => (idx => caesar_config, reg_type => r_w)
  );

  constant caesar_regs_init : caesar_regs_t := (
    0 => "00000000000000000000000001000000"
  );

  -- Cast a 'burst_length_bytes' field value to SLV.
  function to_caesar_config_burst_length_bytes_slv(data : caesar_config_burst_length_bytes_t) return caesar_config_burst_length_bytes_slv_t is
    constant result : caesar_config_burst_length_bytes_slv_t := std_ulogic_vector(to_unsigned(data, caesar_config_burst_length_bytes_width));
  begin
    return result;
  end function;

  -- Get a 'burst_length_bytes' field value from a register value.
  function to_caesar_config_burst_length_bytes(data : reg_t) return caesar_config_burst_length_bytes_t is
    constant result : integer := to_integer(unsigned(data(caesar_config_burst_length_bytes)));
  begin
    return result;
  end function;

  -- Cast a 'increment' field value to SLV.
  function to_caesar_config_increment_slv(data : caesar_config_increment_t) return caesar_config_increment_slv_t is
    constant result : caesar_config_increment_slv_t := std_ulogic_vector(to_signed(data, caesar_config_increment_width));
  begin
    return result;
  end function;

  -- Get a 'increment' field value from a register value.
  function to_caesar_config_increment(data : reg_t) return caesar_config_increment_t is
    constant result : integer := to_integer(signed(data(caesar_config_increment)));
  begin
    return result;
  end function;

  -- Cast a 'retry_count' field value to SLV.
  function to_caesar_config_retry_count_slv(data : caesar_config_retry_count_t) return caesar_config_retry_count_slv_t is
    constant result : caesar_config_retry_count_slv_t := std_ulogic_vector(to_unsigned(data, caesar_config_retry_count_width));
  begin
    return result;
  end function;

  -- Get a 'retry_count' field value from a register value.
  function to_caesar_config_retry_count(data : reg_t) return caesar_config_retry_count_t is
    constant result : integer := to_integer(unsigned(data(caesar_config_retry_count)));
  begin
    return result;
  end function;

end package body;

Record package

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

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

result_data <= input_data + regs_down.config.increment;
Click to expand/collapse code.
Generated VHDL record package.
  1-- This file is automatically generated by hdl-registers version 5.1.4-dev.
  2-- Code generator VhdlRecordPackageGenerator version 1.0.0.
  3-- Generated 2024-04-26 20:51 at commit 2c446088490c1e41.
  4-- Register hash 5bf25bc5ce7e7bb89d3f05d6ed90c19998888575.
  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    burst_length_bytes : caesar_config_burst_length_bytes_t;
 24    increment : caesar_config_increment_t;
 25    retry_count : caesar_config_retry_count_t;
 26  end record;
 27  -- Default value for the 'config' register as a record.
 28  constant caesar_config_init : caesar_config_t := (
 29    burst_length_bytes => caesar_config_burst_length_bytes_init,
 30    increment => caesar_config_increment_init,
 31    retry_count => caesar_config_retry_count_init
 32  );
 33  -- Convert a record of the 'config' register to SLV.
 34  function to_slv(data : caesar_config_t) return reg_t;
 35  -- Convert an SLV register value to the record for the 'config' register.
 36  function to_caesar_config(data : reg_t) return caesar_config_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    config : caesar_config_t;
 44  end record;
 45  -- Default value of the above record.
 46  constant caesar_regs_down_init : caesar_regs_down_t := (
 47    config => caesar_config_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 map.
 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    config : 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 map.
 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    config : 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_config_t) return reg_t is
 89    variable result : reg_t := (others => '-');
 90  begin
 91    result(caesar_config_burst_length_bytes) := to_caesar_config_burst_length_bytes_slv(data.burst_length_bytes);
 92    result(caesar_config_increment) := to_caesar_config_increment_slv(data.increment);
 93    result(caesar_config_retry_count) := to_caesar_config_retry_count_slv(data.retry_count);
 94
 95    return result;
 96  end function;
 97
 98  function to_caesar_config(data : reg_t) return caesar_config_t is
 99    variable result : caesar_config_t := caesar_config_init;
100  begin
101    result.burst_length_bytes := to_caesar_config_burst_length_bytes(data);
102    result.increment := to_caesar_config_increment(data);
103    result.retry_count := to_caesar_config_retry_count(data);
104
105    return result;
106  end function;
107
108  function to_caesar_regs_down(data : caesar_regs_t) return caesar_regs_down_t is
109    variable result : caesar_regs_down_t := caesar_regs_down_init;
110  begin
111    result.config := to_caesar_config(data(caesar_config));
112
113    return result;
114  end function;
115
116  function to_caesar_reg_was_read(
117    data : caesar_reg_was_accessed_t
118  ) return caesar_reg_was_read_t is
119    variable result : caesar_reg_was_read_t := caesar_reg_was_read_init;
120  begin
121    result.config := data(caesar_config);
122
123    return result;
124  end function;
125
126  function to_caesar_reg_was_written(
127    data : caesar_reg_was_accessed_t
128  ) return caesar_reg_was_written_t is
129    variable result : caesar_reg_was_written_t := caesar_reg_was_written_init;
130  begin
131    result.config := data(caesar_config);
132
133    return result;
134  end function;
135
136end package body;

C++

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

The class header is skipped here, since its inclusion would make this page very long. See C++ code generator for more details and an example of how the excluded file might look.

C++ interface header

Note that the setters and getters for each field value use integer types as argument or return value. The signed field uses int32_t while the unsigned fields use uint32_t.

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

C++ implementation

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

Click to expand/collapse code.
Generated C++ class implementation code.
  1// This file is automatically generated by hdl-registers version 5.1.4-dev.
  2// Code generator CppImplementationGenerator version 1.0.0.
  3// Generated 2024-04-26 20:51 at commit 2c446088490c1e41.
  4// Register hash 5bf25bc5ce7e7bb89d3f05d6ed90c19998888575.
  5
  6#include "include/caesar.h"
  7
  8namespace fpga_regs
  9{
 10
 11  Caesar::Caesar(volatile uint8_t *base_address)
 12      : m_registers(reinterpret_cast<volatile uint32_t *>(base_address))
 13  {
 14    // Empty
 15  }
 16
 17  // ---------------------------------------------------------------------------
 18  // Methods for the 'config' register.
 19  // See interface header for documentation.
 20
 21  uint32_t Caesar::get_config() const
 22  {
 23    const size_t index = 0;
 24    const uint32_t result = m_registers[index];
 25
 26    return result;
 27  }
 28
 29  uint32_t Caesar::get_config_burst_length_bytes() const
 30  {
 31    const uint32_t register_value = get_config();
 32    const uint32_t field_value = get_config_burst_length_bytes_from_value(register_value);
 33
 34    return field_value;
 35  }
 36
 37  uint32_t Caesar::get_config_burst_length_bytes_from_value(
 38    uint32_t register_value
 39  ) const
 40  {
 41    const uint32_t shift = 0uL;
 42    const uint32_t mask_at_base = 0b111111111uL;
 43    const uint32_t mask_shifted = mask_at_base << shift;
 44
 45    const uint32_t result_masked = register_value & mask_shifted;
 46    const uint32_t result_shifted = result_masked >> shift;
 47
 48    uint32_t field_value;
 49
 50    // No casting needed.
 51    field_value = result_shifted;
 52
 53    // Check that field value is within the legal range.
 54    assert(field_value >= 1);
 55    assert(field_value <= 256);
 56
 57    return field_value;
 58  }
 59
 60  int32_t Caesar::get_config_increment() const
 61  {
 62    const uint32_t register_value = get_config();
 63    const int32_t field_value = get_config_increment_from_value(register_value);
 64
 65    return field_value;
 66  }
 67
 68  int32_t Caesar::get_config_increment_from_value(
 69    uint32_t register_value
 70  ) const
 71  {
 72    const uint32_t shift = 9uL;
 73    const uint32_t mask_at_base = 0b111uL;
 74    const uint32_t mask_shifted = mask_at_base << shift;
 75
 76    const uint32_t result_masked = register_value & mask_shifted;
 77    const uint32_t result_shifted = result_masked >> shift;
 78
 79    int32_t field_value;
 80
 81    const int32_t sign_bit_mask = 1 << 2;
 82
 83    if (result_shifted & sign_bit_mask)
 84    {
 85      // Value is to be interpreted as negative.
 86      // Sign extend it from the width of the field to the width of the return type.
 87      field_value = result_shifted - 2 * sign_bit_mask;
 88    }
 89    else
 90    {
 91      // Value is positive.
 92      field_value = result_shifted;
 93    }
 94
 95    // Check that field value is within the legal range.
 96    assert(field_value >= -4);
 97    assert(field_value <= 3);
 98
 99    return field_value;
100  }
101
102  uint32_t Caesar::get_config_retry_count() const
103  {
104    const uint32_t register_value = get_config();
105    const uint32_t field_value = get_config_retry_count_from_value(register_value);
106
107    return field_value;
108  }
109
110  uint32_t Caesar::get_config_retry_count_from_value(
111    uint32_t register_value
112  ) const
113  {
114    const uint32_t shift = 12uL;
115    const uint32_t mask_at_base = 0b111uL;
116    const uint32_t mask_shifted = mask_at_base << shift;
117
118    const uint32_t result_masked = register_value & mask_shifted;
119    const uint32_t result_shifted = result_masked >> shift;
120
121    uint32_t field_value;
122
123    // No casting needed.
124    field_value = result_shifted;
125
126    // Check that field value is within the legal range.
127    assert(field_value >= 0);
128    assert(field_value <= 5);
129
130    return field_value;
131  }
132
133  void Caesar::set_config(
134    uint32_t register_value
135  ) const
136  {
137    const size_t index = 0;
138    m_registers[index] = register_value;
139  }
140
141  void Caesar::set_config_burst_length_bytes(
142    uint32_t field_value
143  ) const
144  {
145    // Get the current value of other fields by reading register on the bus.
146    const uint32_t current_register_value = get_config();
147    const uint32_t result_register_value = set_config_burst_length_bytes_from_value(current_register_value, field_value);
148    set_config(result_register_value);
149  }
150
151  uint32_t Caesar::set_config_burst_length_bytes_from_value(
152    uint32_t register_value,
153    uint32_t field_value
154  ) const  {
155    const uint32_t shift = 0uL;
156    const uint32_t mask_at_base = 0b111111111uL;
157    const uint32_t mask_shifted = mask_at_base << shift;
158
159    // Check that field value is within the legal range.
160    assert(field_value >= 1);
161    assert(field_value <= 256);
162
163    const uint32_t field_value_masked = field_value & mask_at_base;
164    const uint32_t field_value_masked_and_shifted = field_value_masked << shift;
165
166    const uint32_t mask_shifted_inverse = ~mask_shifted;
167    const uint32_t register_value_masked = register_value & mask_shifted_inverse;
168
169    const uint32_t result_register_value = register_value_masked | field_value_masked_and_shifted;
170
171    return result_register_value;
172  }
173
174  void Caesar::set_config_increment(
175    int32_t field_value
176  ) const
177  {
178    // Get the current value of other fields by reading register on the bus.
179    const uint32_t current_register_value = get_config();
180    const uint32_t result_register_value = set_config_increment_from_value(current_register_value, field_value);
181    set_config(result_register_value);
182  }
183
184  uint32_t Caesar::set_config_increment_from_value(
185    uint32_t register_value,
186    int32_t field_value
187  ) const  {
188    const uint32_t shift = 9uL;
189    const uint32_t mask_at_base = 0b111uL;
190    const uint32_t mask_shifted = mask_at_base << shift;
191
192    // Check that field value is within the legal range.
193    assert(field_value >= -4);
194    assert(field_value <= 3);
195
196    const uint32_t field_value_masked = field_value & mask_at_base;
197    const uint32_t field_value_masked_and_shifted = field_value_masked << shift;
198
199    const uint32_t mask_shifted_inverse = ~mask_shifted;
200    const uint32_t register_value_masked = register_value & mask_shifted_inverse;
201
202    const uint32_t result_register_value = register_value_masked | field_value_masked_and_shifted;
203
204    return result_register_value;
205  }
206
207  void Caesar::set_config_retry_count(
208    uint32_t field_value
209  ) const
210  {
211    // Get the current value of other fields by reading register on the bus.
212    const uint32_t current_register_value = get_config();
213    const uint32_t result_register_value = set_config_retry_count_from_value(current_register_value, field_value);
214    set_config(result_register_value);
215  }
216
217  uint32_t Caesar::set_config_retry_count_from_value(
218    uint32_t register_value,
219    uint32_t field_value
220  ) const  {
221    const uint32_t shift = 12uL;
222    const uint32_t mask_at_base = 0b111uL;
223    const uint32_t mask_shifted = mask_at_base << shift;
224
225    // Check that field value is within the legal range.
226    assert(field_value >= 0);
227    assert(field_value <= 5);
228
229    const uint32_t field_value_masked = field_value & mask_at_base;
230    const uint32_t field_value_masked_and_shifted = field_value_masked << shift;
231
232    const uint32_t mask_shifted_inverse = ~mask_shifted;
233    const uint32_t register_value_masked = register_value & mask_shifted_inverse;
234
235    const uint32_t result_register_value = register_value_masked | field_value_masked_and_shifted;
236
237    return result_register_value;
238  }
239
240} /* 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// This file is automatically generated by hdl-registers version 5.1.4-dev.
 2// Code generator CHeaderGenerator version 1.0.0.
 3// Generated 2024-04-26 20:51 at commit 2c446088490c1e41.
 4// Register hash 5bf25bc5ce7e7bb89d3f05d6ed90c19998888575.
 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 'burst_length_bytes' field in the 'config' register.
25#define CAESAR_CONFIG_BURST_LENGTH_BYTES_SHIFT (0u)
26#define CAESAR_CONFIG_BURST_LENGTH_BYTES_MASK (0b111111111u << 0u)
27#define CAESAR_CONFIG_BURST_LENGTH_BYTES_MASK_INVERSE (~CAESAR_CONFIG_BURST_LENGTH_BYTES_MASK)
28// Attributes for the 'increment' field in the 'config' register.
29#define CAESAR_CONFIG_INCREMENT_SHIFT (9u)
30#define CAESAR_CONFIG_INCREMENT_MASK (0b111u << 9u)
31#define CAESAR_CONFIG_INCREMENT_MASK_INVERSE (~CAESAR_CONFIG_INCREMENT_MASK)
32// Attributes for the 'retry_count' field in the 'config' register.
33#define CAESAR_CONFIG_RETRY_COUNT_SHIFT (12u)
34#define CAESAR_CONFIG_RETRY_COUNT_MASK (0b111u << 12u)
35#define CAESAR_CONFIG_RETRY_COUNT_MASK_INVERSE (~CAESAR_CONFIG_RETRY_COUNT_MASK)
36
37#endif // CAESAR_REGS_H