Default registers

Many projects use a few default registers in standard locations that shall be present in all modules. For example, very commonly the first register of a module is an interrupt status register and the second one is an interrupt mask. In order to handle this, without having to duplicate names and descriptions in many places, there is a default_registers flag to the from_toml() function. Passing a list of Register objects will insert these registers first in the RegisterList.

Usage in TOML

The TOML file below is used to showcase insertion of default registers.

TOML for showcasing default registers.
 1# Adapt the "interrupt_status" default register for the needs of this register list.
 2[interrupt_status]
 3
 4# The "mode" property MUST NOT be present for a default register.
 5# The mode of the register is set in the default register object in Python.
 6
 7# The "description" property is OPTIONAL for a default register.
 8# If specified, it will only be set in this register list, not other register lists that also
 9# use this default register.
10# If not specified, the description of the default register object in Python will be used.
11description = "Interrupt status for my module."
12
13# Register fields can be added freely to a default register.
14# Will only be added to this register list, not other register lists that also use
15# this default register.
16overflow.type = "bit"
17overflow.description = "Too high data rate."
18
19underflow.type = "bit"
20underflow.description = "Too low data rate."
21
22# Note that the "interrupt_mask" default register is not adapted here.
23# It will be included in this register list at its default configuration.
24
25# Further registers and register arrays can be added freely after the default registers.
26[config]
27
28mode = "r_w"
29description = "Generic configuration register."

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 to showcase default registers.
 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.interface import CppInterfaceGenerator
 8from hdl_registers.generator.html.page import HtmlPageGenerator
 9from hdl_registers.generator.vhdl.register_package import VhdlRegisterPackageGenerator
10from hdl_registers.parser.toml import from_toml
11from hdl_registers.register import Register
12from hdl_registers.register_list import RegisterList
13from hdl_registers.register_modes import REGISTER_MODES
14
15THIS_DIR = Path(__file__).parent
16
17
18DEFAULT_REGISTERS = [
19    Register(
20        name="interrupt_status",
21        index=0,
22        mode=REGISTER_MODES["r_wpulse"],
23        description="Interrupt status. Clear interrupt(s) by writing the corresponding bitmask.",
24    ),
25    Register(
26        name="interrupt_mask",
27        index=1,
28        mode=REGISTER_MODES["r_w"],
29        description="Enable or disable interrupts by setting bitmask.",
30    ),
31]
32
33
34def parse_toml() -> RegisterList:
35    """
36    Create the register list by parsing a TOML data file.
37    """
38    return from_toml(
39        name="caesar",
40        toml_file=THIS_DIR.parent / "toml" / "basic_feature_default_registers.toml",
41        default_registers=DEFAULT_REGISTERS,
42    )
43
44
45def create_from_api() -> RegisterList:
46    """
47    Alternative method: Create the register list by using the Python API.
48    """
49    register_list = RegisterList.from_default_registers(
50        name="caesar", source_definition_file=None, default_registers=DEFAULT_REGISTERS
51    )
52
53    interrupt_status = register_list.get_register(register_name="interrupt_status")
54    interrupt_status.description = "Interrupt status for my module."
55    interrupt_status.append_bit(
56        name="overflow", description="Too high data rate.", default_value="0"
57    )
58    interrupt_status.append_bit(
59        name="underflow", description="Too low data rate.", default_value="0"
60    )
61
62    register_list.append_register(
63        name="config", mode=REGISTER_MODES["r_w"], description="Generic configuration register."
64    )
65
66    return register_list
67
68
69def generate(register_list: RegisterList, output_folder: Path):
70    """
71    Generate the artifacts that we are interested in.
72    """
73    CHeaderGenerator(register_list=register_list, output_folder=output_folder).create()
74    CppInterfaceGenerator(register_list=register_list, output_folder=output_folder).create()
75    HtmlPageGenerator(register_list=register_list, output_folder=output_folder).create()
76    VhdlRegisterPackageGenerator(register_list=register_list, output_folder=output_folder).create()
77
78
79def main(output_folder: Path):
80    generate(register_list=parse_toml(), output_folder=output_folder / "toml")
81    generate(register_list=create_from_api(), output_folder=output_folder / "api")
82
83
84if __name__ == "__main__":
85    main(output_folder=Path(sys.argv[1]))

See RegisterList.from_default_registers() for more Python API details.

Generated code

See below for a description of the code that can be generated when using register arrays.

HTML page

See HTML file below for the human-readable documentation that is produced by the generate() call in the Python example above.

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.

Click to expand/collapse code.
Generated VHDL code.
 1-- This file is automatically generated by hdl-registers version 6.2.1-dev.
 2-- Code generator VhdlRegisterPackageGenerator version 1.0.0.
 3-- Generated 2024-12-19 20:52 at commit cd01ff93f646632c.
 4-- Register hash 8c0e8391ad087478739e47ddc075f056e1c63641.
 5
 6library ieee;
 7use ieee.std_logic_1164.all;
 8use ieee.numeric_std.all;
 9use ieee.fixed_pkg.all;
10
11library reg_file;
12use reg_file.reg_file_pkg.all;
13
14
15package caesar_regs_pkg is
16
17  -- ---------------------------------------------------------------------------
18  -- The valid range of register indexes.
19  subtype caesar_reg_range is natural range 0 to 2;
20
21  -- Register indexes, within the list of registers.
22  constant caesar_interrupt_status : natural := 0;
23  constant caesar_interrupt_mask : natural := 1;
24  constant caesar_config : natural := 2;
25
26  -- Declare 'reg_map' and 'regs_init' constants here but define them in body (deferred constants).
27  -- So that functions have been elaborated when they are called.
28  -- Needed for ModelSim compilation to pass.
29
30  -- To be used as the 'regs' generic of 'axi_lite_reg_file.vhd'.
31  constant caesar_reg_map : reg_definition_vec_t(caesar_reg_range);
32
33  -- To be used for the 'regs_up' and 'regs_down' ports of 'axi_lite_reg_file.vhd'.
34  subtype caesar_regs_t is reg_vec_t(caesar_reg_range);
35  -- To be used as the 'default_values' generic of 'axi_lite_reg_file.vhd'.
36  constant caesar_regs_init : caesar_regs_t;
37
38  -- To be used for the 'reg_was_read' and 'reg_was_written' ports of 'axi_lite_reg_file.vhd'.
39  subtype caesar_reg_was_accessed_t is std_ulogic_vector(caesar_reg_range);
40
41  -- -----------------------------------------------------------------------------
42  -- Fields in the 'interrupt_status' register.
43  -- Range of the 'overflow' field.
44  constant caesar_interrupt_status_overflow : natural := 0;
45  -- Default value of the 'overflow' field.
46  constant caesar_interrupt_status_overflow_init : std_ulogic := '0';
47
48  -- Range of the 'underflow' field.
49  constant caesar_interrupt_status_underflow : natural := 1;
50  -- Default value of the 'underflow' field.
51  constant caesar_interrupt_status_underflow_init : std_ulogic := '0';
52
53end package;
54
55package body caesar_regs_pkg is
56
57  constant caesar_reg_map : reg_definition_vec_t(caesar_reg_range) := (
58    0 => (idx => caesar_interrupt_status, reg_type => r_wpulse),
59    1 => (idx => caesar_interrupt_mask, reg_type => r_w),
60    2 => (idx => caesar_config, reg_type => r_w)
61  );
62
63  constant caesar_regs_init : caesar_regs_t := (
64    0 => "00000000000000000000000000000000",
65    1 => "00000000000000000000000000000000",
66    2 => "00000000000000000000000000000000"
67  );
68
69end package body;

C++ interface header

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

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

C header

The C code below is produced by the generate() call in the Python example above. Click the button to expand and view the code.

Click to expand/collapse code.
Generated C code.
 1// This file is automatically generated by hdl-registers version 6.2.1-dev.
 2// Code generator CHeaderGenerator version 1.0.0.
 3// Generated 2024-12-19 20:52 at commit cd01ff93f646632c.
 4// Register hash 8c0e8391ad087478739e47ddc075f056e1c63641.
 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 (3u)
12
13// Type for this register map.
14typedef struct caesar_regs_t
15{
16  // Mode "Read, Write-pulse".
17  uint32_t interrupt_status;
18  // Mode "Read, Write".
19  uint32_t interrupt_mask;
20  // Mode "Read, Write".
21  uint32_t config;
22} caesar_regs_t;
23
24// Address of the 'interrupt_status' register.
25// Mode 'Read, Write-pulse'.
26#define CAESAR_INTERRUPT_STATUS_INDEX (0u)
27#define CAESAR_INTERRUPT_STATUS_ADDR (4u * CAESAR_INTERRUPT_STATUS_INDEX)
28// Attributes for the 'overflow' field in the 'interrupt_status' register.
29#define CAESAR_INTERRUPT_STATUS_OVERFLOW_SHIFT (0u)
30#define CAESAR_INTERRUPT_STATUS_OVERFLOW_MASK (0b1u << 0u)
31#define CAESAR_INTERRUPT_STATUS_OVERFLOW_MASK_INVERSE (~CAESAR_INTERRUPT_STATUS_OVERFLOW_MASK)
32// Attributes for the 'underflow' field in the 'interrupt_status' register.
33#define CAESAR_INTERRUPT_STATUS_UNDERFLOW_SHIFT (1u)
34#define CAESAR_INTERRUPT_STATUS_UNDERFLOW_MASK (0b1u << 1u)
35#define CAESAR_INTERRUPT_STATUS_UNDERFLOW_MASK_INVERSE (~CAESAR_INTERRUPT_STATUS_UNDERFLOW_MASK)
36
37// Address of the 'interrupt_mask' register.
38// Mode 'Read, Write'.
39#define CAESAR_INTERRUPT_MASK_INDEX (1u)
40#define CAESAR_INTERRUPT_MASK_ADDR (4u * CAESAR_INTERRUPT_MASK_INDEX)
41
42// Address of the 'config' register.
43// Mode 'Read, Write'.
44#define CAESAR_CONFIG_INDEX (2u)
45#define CAESAR_CONFIG_ADDR (4u * CAESAR_CONFIG_INDEX)
46
47#endif // CAESAR_REGS_H