Skip to main content

Register Maps

A register map is a collection of register map elements such as registers, register arrays and memories.

In the generated code, a register map translates to a VHDL component or a SystemVerilog module with an AXI4-lite interface on the host-facing side. On the user logic side, one or more dedicated ports are available for every register field. The direction of the port depends on the type of the register field:

  • Control (read-write or write-only) register fields are mapped to output ports
  • Status (read-only) and interrupt register fields are mapped to input ports

The following listing shows the generated VHDL entity for a register map called my_map with a default base address of 0xA000_0000 that is organized as follows:

  • A control register called control with a 1-bit ena field and an 16-bit config field
  • A status register called status with an 8-bit state field
  • An interrupt register called irq with two 1-bit overflow and underflow fields

The SytemVerilog code looks very similar to the VHDL code shown below.

entity my_map_regs is
generic(
AXI_ADDR_WIDTH : integer := 32; -- width of the AXI address bus
BASEADDR : std_logic_vector(31 downto 0) := x"A0000000" -- the register file's system base address
);
port(
-- Clock and Reset
axi_aclk : in std_logic;
axi_aresetn : in std_logic;
-- AXI Write Address Channel
s_axi_awaddr : in std_logic_vector(AXI_ADDR_WIDTH - 1 downto 0);
s_axi_awprot : in std_logic_vector(2 downto 0); -- sigasi @suppress "Unused port"
s_axi_awvalid : in std_logic;
s_axi_awready : out std_logic;
-- AXI Write Data Channel
s_axi_wdata : in std_logic_vector(31 downto 0);
s_axi_wstrb : in std_logic_vector(3 downto 0);
s_axi_wvalid : in std_logic;
s_axi_wready : out std_logic;
-- AXI Read Address Channel
s_axi_araddr : in std_logic_vector(AXI_ADDR_WIDTH - 1 downto 0);
s_axi_arprot : in std_logic_vector(2 downto 0); -- sigasi @suppress "Unused port"
s_axi_arvalid : in std_logic;
s_axi_arready : out std_logic;
-- AXI Read Data Channel
s_axi_rdata : out std_logic_vector(31 downto 0);
s_axi_rresp : out std_logic_vector(1 downto 0);
s_axi_rvalid : out std_logic;
s_axi_rready : in std_logic;
-- AXI Write Response Channel
s_axi_bresp : out std_logic_vector(1 downto 0);
s_axi_bvalid : out std_logic;
s_axi_bready : in std_logic;
-- User Ports
control_strobe : out std_logic; -- Strobe signal for register 'control' (pulsed when the register is written from the bus)
control_ena : out std_logic_vector(0 downto 0); -- Value of register 'control', field 'ena'
control_config : out std_logic_vector(15 downto 0); -- Value of register 'control', field 'config'
status_strobe : out std_logic; -- Strobe signal for register 'status' (pulsed when the register is read from the bus)
status_state : in std_logic_vector(7 downto 0); -- Value of register 'status', field 'state'
irq_overflow_set : in std_logic; -- Set signal for register 'irq', field 'overflow' (pulse to set the field to '1')
irq_underflow_set : in std_logic -- Set signal for register 'irq', field 'underflow' (pulse to set the field to '1')
);
end entity my_map_regs;

Let's have a look at this entity:

  • The generic parameter BASEADDR allows you to set the base address of the register bank in the system address space; this is particularly useful for systems where you have several instances of the same register bank.

  • The axi_aclk, axi_aresetn and the s_axi_* ports form the AXI4-lite interface of the register bank.

  • The user ports are the interface to the user logic:

    • The control_strobe port is pulsed every time the control register is written from the bus.
    • The control_ena port reflects the value of the control.ena field.
    • The control_config port reflects the value of the config.control field.
    • The status_strobe port is pulsed every time the status register is read from the bus.
    • The status_state port drives the value of the status.state field.
    • The irq_overflow_set port can be used to set the irq.overflow field from the user logic (note that this field cannot be reset from the user logic, it can only be reset from the bus by writing a 1 to it).
    • The irq_underflow_set port can be used to set the irq.underflow field from the user logic.

To avoid excessive port proliferation in larger register maps, you can group the user ports into VHDL records. In that case, the VHDL entity looks like this:

entity my_map_regs is
generic(
AXI_ADDR_WIDTH : integer := 32; -- width of the AXI address bus
BASEADDR : std_logic_vector(31 downto 0) := x"A0000000" -- the register file's system base address
);
port(
-- Clock and Reset
axi_aclk : in std_logic;
axi_aresetn : in std_logic;
-- AXI Write Address Channel
s_axi_awaddr : in std_logic_vector(AXI_ADDR_WIDTH - 1 downto 0);
s_axi_awprot : in std_logic_vector(2 downto 0); -- sigasi @suppress "Unused port"
s_axi_awvalid : in std_logic;
s_axi_awready : out std_logic;
-- AXI Write Data Channel
s_axi_wdata : in std_logic_vector(31 downto 0);
s_axi_wstrb : in std_logic_vector(3 downto 0);
s_axi_wvalid : in std_logic;
s_axi_wready : out std_logic;
-- AXI Read Address Channel
s_axi_araddr : in std_logic_vector(AXI_ADDR_WIDTH - 1 downto 0);
s_axi_arprot : in std_logic_vector(2 downto 0); -- sigasi @suppress "Unused port"
s_axi_arvalid : in std_logic;
s_axi_arready : out std_logic;
-- AXI Read Data Channel
s_axi_rdata : out std_logic_vector(31 downto 0);
s_axi_rresp : out std_logic_vector(1 downto 0);
s_axi_rvalid : out std_logic;
s_axi_rready : in std_logic;
-- AXI Write Response Channel
s_axi_bresp : out std_logic_vector(1 downto 0);
s_axi_bvalid : out std_logic;
s_axi_bready : in std_logic;
-- User Ports
user2regs : in user2regs_t;
regs2user : out regs2user_t
);
end entity my_map_regs;

The user2regs_t and regs2user_t types are VHDL records; they are defined in the VHDL package corresponding to the generated component:

-- User-logic ports (from user-logic to register file)
type user2regs_t is record
status_state : std_logic_vector(7 downto 0); -- value of register 'status', field 'state'
irq_overflow_set : std_logic; -- set signal for register 'irq', field 'overflow' (pulse to set the field to '1')
irq_underflow_set : std_logic; -- set signal for register 'irq', field 'underflow' (pulse to set the field to '1')
end record;

-- User-logic ports (from register file to user-logic)
type regs2user_t is record
control_strobe : std_logic; -- Strobe signal for register 'control' (pulsed when the register is written from the bus}
control_ena : std_logic_vector(0 downto 0); -- Value of register 'control', field 'ena'
control_config : std_logic_vector(15 downto 0); -- Value of register 'control', field 'config'
status_strobe : std_logic; -- Strobe signal for register 'status' (pulsed when the register is read from the bus}
end record;