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[register.config]
 2
 3mode = "r_w"
 4description = "Generic configuration register."
 5
 6
 7[register.status]
 8
 9mode = "r"
10description = "Generic status 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
13
14THIS_DIR = Path(__file__).parent
15
16
17DEFAULT_REGISTERS = [
18    Register(
19        name="interrupt_status",
20        index=0,
21        mode="r_wpulse",
22        description="Interrupt status. Clear interrupt(s) by writing the corresponding bitmask.",
23    ),
24    Register(
25        name="interrupt_mask",
26        index=1,
27        mode="r_w",
28        description="Enable or disable interrupts by setting bitmask.",
29    ),
30]
31
32
33def parse_toml() -> RegisterList:
34    """
35    Create the register list by parsing a TOML data file.
36    """
37    return from_toml(
38        name="caesar",
39        toml_file=THIS_DIR.parent / "toml" / "basic_feature_default_registers.toml",
40        default_registers=DEFAULT_REGISTERS,
41    )
42
43
44def create_from_api() -> RegisterList:
45    """
46    Alternative method: Create the register list by using the Python API.
47    """
48    register_list = RegisterList.from_default_registers(
49        name="caesar", source_definition_file=None, default_registers=DEFAULT_REGISTERS
50    )
51
52    register_list.append_register(
53        name="config", mode="r_w", description="Generic configuration register."
54    )
55
56    register_list.append_register(name="status", mode="r", description="Generic status register.")
57
58    return register_list
59
60
61def generate(register_list: RegisterList, output_folder: Path):
62    """
63    Generate the artifacts that we are interested in.
64    """
65    CHeaderGenerator(register_list=register_list, output_folder=output_folder).create()
66    CppInterfaceGenerator(register_list=register_list, output_folder=output_folder).create()
67    HtmlPageGenerator(register_list=register_list, output_folder=output_folder).create()
68    VhdlRegisterPackageGenerator(register_list=register_list, output_folder=output_folder).create()
69
70
71def main(output_folder: Path):
72    generate(register_list=parse_toml(), output_folder=output_folder / "toml")
73    generate(register_list=create_from_api(), output_folder=output_folder / "api")
74
75
76if __name__ == "__main__":
77    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 5.1.4-dev.
 2-- Code generator VhdlRegisterPackageGenerator version 1.0.0.
 3-- Generated 2024-04-27 20:52 at commit 2c446088490c1e41.
 4-- Register hash 07ff9f5d363999ae8dc20a7f7f97a7f485a74abb.
 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 3;
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  constant caesar_status : natural := 3;
26
27  -- Declare 'reg_map' and 'regs_init' constants here but define them in body (deferred constants).
28  -- So that functions have been elaborated when they are called.
29  -- Needed for ModelSim compilation to pass.
30
31  -- To be used as the 'regs' generic of 'axi_lite_reg_file.vhd'.
32  constant caesar_reg_map : reg_definition_vec_t(caesar_reg_range);
33
34  -- To be used for the 'regs_up' and 'regs_down' ports of 'axi_lite_reg_file.vhd'.
35  subtype caesar_regs_t is reg_vec_t(caesar_reg_range);
36  -- To be used as the 'default_values' generic of 'axi_lite_reg_file.vhd'.
37  constant caesar_regs_init : caesar_regs_t;
38
39  -- To be used for the 'reg_was_read' and 'reg_was_written' ports of 'axi_lite_reg_file.vhd'.
40  subtype caesar_reg_was_accessed_t is std_ulogic_vector(caesar_reg_range);
41
42end package;
43
44package body caesar_regs_pkg is
45
46  constant caesar_reg_map : reg_definition_vec_t(caesar_reg_range) := (
47    0 => (idx => caesar_interrupt_status, reg_type => r_wpulse),
48    1 => (idx => caesar_interrupt_mask, reg_type => r_w),
49    2 => (idx => caesar_config, reg_type => r_w),
50    3 => (idx => caesar_status, reg_type => r)
51  );
52
53  constant caesar_regs_init : caesar_regs_t := (
54    0 => "00000000000000000000000000000000",
55    1 => "00000000000000000000000000000000",
56    2 => "00000000000000000000000000000000",
57    3 => "00000000000000000000000000000000"
58  );
59
60end 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 5.1.4-dev.
 2// Code generator CppInterfaceGenerator version 1.0.0.
 3// Generated 2024-04-27 20:52 at commit 2c446088490c1e41.
 4// Register hash 07ff9f5d363999ae8dc20a7f7f97a7f485a74abb.
 5
 6#pragma once
 7
 8#include <cassert>
 9#include <cstdint>
10#include <cstdlib>
11
12namespace fpga_regs
13{
14
15  class ICaesar
16  {
17  public:
18    // Number of registers within this register map.
19    static const size_t num_registers = 4uL;
20
21    virtual ~ICaesar() {}
22
23    // -------------------------------------------------------------------------
24    // Methods for the 'interrupt_status' register. Mode 'Read, Write-pulse'.
25
26    // Getter that will read the whole register's value over the register bus.
27    virtual uint32_t get_interrupt_status() const = 0;
28
29    // Setter that will write the whole register's value over the register bus.
30    virtual void set_interrupt_status(
31      uint32_t register_value
32    ) const = 0;
33
34    // -------------------------------------------------------------------------
35    // Methods for the 'interrupt_mask' register. Mode 'Read, Write'.
36
37    // Getter that will read the whole register's value over the register bus.
38    virtual uint32_t get_interrupt_mask() const = 0;
39
40    // Setter that will write the whole register's value over the register bus.
41    virtual void set_interrupt_mask(
42      uint32_t register_value
43    ) const = 0;
44
45    // -------------------------------------------------------------------------
46    // Methods for the 'config' register. Mode 'Read, Write'.
47
48    // Getter that will read the whole register's value over the register bus.
49    virtual uint32_t get_config() const = 0;
50
51    // Setter that will write the whole register's value over the register bus.
52    virtual void set_config(
53      uint32_t register_value
54    ) const = 0;
55
56    // -------------------------------------------------------------------------
57    // Methods for the 'status' register. Mode 'Read'.
58
59    // Getter that will read the whole register's value over the register bus.
60    virtual uint32_t get_status() const = 0;
61
62  };
63
64} /* 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 5.1.4-dev.
 2// Code generator CHeaderGenerator version 1.0.0.
 3// Generated 2024-04-27 20:52 at commit 2c446088490c1e41.
 4// Register hash 07ff9f5d363999ae8dc20a7f7f97a7f485a74abb.
 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 (4u)
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  // Mode "Read".
23  uint32_t status;
24} caesar_regs_t;
25
26// Address of the 'interrupt_status' register.
27// Mode 'Read, Write-pulse'.
28#define CAESAR_INTERRUPT_STATUS_INDEX (0u)
29#define CAESAR_INTERRUPT_STATUS_ADDR (4u * CAESAR_INTERRUPT_STATUS_INDEX)
30
31// Address of the 'interrupt_mask' register.
32// Mode 'Read, Write'.
33#define CAESAR_INTERRUPT_MASK_INDEX (1u)
34#define CAESAR_INTERRUPT_MASK_ADDR (4u * CAESAR_INTERRUPT_MASK_INDEX)
35
36// Address of the 'config' register.
37// Mode 'Read, Write'.
38#define CAESAR_CONFIG_INDEX (2u)
39#define CAESAR_CONFIG_ADDR (4u * CAESAR_CONFIG_INDEX)
40
41// Address of the 'status' register.
42// Mode 'Read'.
43#define CAESAR_STATUS_INDEX (3u)
44#define CAESAR_STATUS_ADDR (4u * CAESAR_STATUS_INDEX)
45
46#endif // CAESAR_REGS_H