VHDL code generator
A large ecosystem of VHDL artifacts can be generated that support both implementation and simulation in your project. See the Example below for a real-world use case of all these artifacts.
VhdlRegisterPackageGenerator
generates the base VHDL package with register indexes and modes, field indexes, field types, and field conversion functions.VhdlRecordPackageGenerator
generates a VHDL package with register records that use native VHDL types for all fields, along with conversion functions for these.VhdlAxiLiteWrapperGenerator
generates a VHDL entity that wraps an AXI-Lite general register file, and exposes register values to application using the natively typed records.VhdlSimulationReadWritePackageGenerator
generates a VHDL simulation support package with procedures for reading/writing register or field values.VhdlSimulationCheckPackageGenerator
generates a VHDL simulation support package with procedures for checking current register and field values against a given expected value.VhdlSimulationWaitUntilPackageGenerator
generates a VHDL simulation support package with procedures for waiting until a readable register or field assumes a given value.
The recommended workflow is to generate the register file wrapper from
VhdlAxiLiteWrapperGenerator
and instantiate it in your VHDL design.
With this, registers and their field values are available as native VHDL typed values, requiring
no conversion.
See the example below for an example of this.
Example
To illustrate the code generators and how to use the code from them in an effective way, there is a complete VHDL entity and testbench below. While the application (a counter that periodically sends out a pulse) is silly, the goal of the example is to showcase as many of the features as possible and how to efficiently use them.
Register definition TOML file
The registers are generated from the TOML file below. Note that there are three registers of different modes: “Read, Write”, “Write-pulse” and “Read”. In the registers there are a few different fields, of type bit, integer and enumeration.
Click to expand/collapse code.
1################################################################################
2[config]
3
4mode = "r_w"
5
6condition.type = "enumeration"
7condition.description = "Set mode for how the counter operates."
8condition.element.clock_cycles = "Increment counter each clock cycle."
9condition.element.clock_cycles_with_enable = """
10Increment counter each clock cycle when **clock_enable** is asserted.
11"""
12condition.element.enable_edges = """
13Increment counter each time **clock_enable** changes state.
14"""
15
16increment.type = "integer"
17increment.description = "How much to increment counter."
18increment.max_value = 15
19
20
21################################################################################
22[command]
23
24mode = "wpulse"
25
26start.type = "bit"
27start.description = "Write '1' to start operation."
28
29stop.type = "bit"
30stop.description = "Write '1' to stop operation."
31
32
33################################################################################
34[status]
35
36mode = "r"
37
38enabled.type = "bit"
39enabled.description = "Reads as '1' if operation is enabled."
40
41pulse_count.type = "integer"
42pulse_count.max_value = 255
43pulse_count.description = """
44Number of pulses that have been sent.
45Will wrap around.
46Value will be cleared to zero when **config** register is written.
47"""
Python file to generate register artifacts
The Python code below is used to parse the above TOML file and generate all the VHDL code we need for our VHDL implementation and testbench.
Click to expand/collapse code.
1# Standard libraries
2import sys
3from pathlib import Path
4
5# First party libraries
6from hdl_registers.generator.vhdl.axi_lite.wrapper import VhdlAxiLiteWrapperGenerator
7from hdl_registers.generator.vhdl.record_package import VhdlRecordPackageGenerator
8from hdl_registers.generator.vhdl.register_package import VhdlRegisterPackageGenerator
9from hdl_registers.generator.vhdl.simulation.check_package import (
10 VhdlSimulationCheckPackageGenerator,
11)
12from hdl_registers.generator.vhdl.simulation.read_write_package import (
13 VhdlSimulationReadWritePackageGenerator,
14)
15from hdl_registers.generator.vhdl.simulation.wait_until_package import (
16 VhdlSimulationWaitUntilPackageGenerator,
17)
18from hdl_registers.parser.toml import from_toml
19
20THIS_DIR = Path(__file__).parent
21
22
23def main(output_folder: Path):
24 """
25 Create register VHDL artifacts from the "counter" example module.
26 """
27 register_list = from_toml(
28 name="counter", toml_file=THIS_DIR.parent / "sim" / "regs_counter.toml"
29 )
30
31 VhdlRegisterPackageGenerator(
32 register_list=register_list, output_folder=output_folder
33 ).create_if_needed()
34
35 VhdlRecordPackageGenerator(
36 register_list=register_list, output_folder=output_folder
37 ).create_if_needed()
38
39 VhdlAxiLiteWrapperGenerator(
40 register_list=register_list, output_folder=output_folder
41 ).create_if_needed()
42
43 VhdlSimulationReadWritePackageGenerator(
44 register_list=register_list, output_folder=output_folder
45 ).create_if_needed()
46
47 VhdlSimulationCheckPackageGenerator(
48 register_list=register_list, output_folder=output_folder
49 ).create_if_needed()
50
51 VhdlSimulationWaitUntilPackageGenerator(
52 register_list=register_list, output_folder=output_folder
53 ).create_if_needed()
54
55
56if __name__ == "__main__":
57 main(output_folder=Path(sys.argv[1]))
VHDL example implementation
The VHDL below is the implementation of our example counter. Once again, the application is a bit silly, but it does showcase a lot of interesting features.
The entity uses an AXI-Lite register bus and instantiates the register file produced by
VhdlAxiLiteWrapperGenerator
, which can be seen below.Register values up and down are record types from the package produced by
VhdlRecordPackageGenerator
, which can be seen below.The
set_status
process showsHow to access bit fields in a “Write-pulse” register and how to set bit fields in a “Read” register.
How to set and update an integer field in a “Read” register.
How to perform an action when a specific register is written on the register bus.
Note how all the operations are performed using native VHDL types (
std_ulogic
,integer
).The
count
process shows
How to take different action depending on an enumeration field in a “Read, Write” register. Note that the field type is a VHDL enum with its elements (e.g.
condition_clock_cycles
) exposed.How to use a numeric value from a “Read, Write” register. Since the field is of integer type, it can simply be added to another integer.
Click to expand/collapse code.
1-- -------------------------------------------------------------------------------------------------
2-- Regularly send out a 'pulse', with a frequency that is configurable over the register bus.
3-- -------------------------------------------------------------------------------------------------
4
5library ieee;
6use ieee.std_logic_1164.all;
7
8library axi_lite;
9use axi_lite.axi_lite_pkg.all;
10
11library common;
12use common.types_pkg.all;
13
14use work.counter_regs_pkg.all;
15use work.counter_register_record_pkg.all;
16
17
18entity counter is
19 port (
20 clk : in std_ulogic;
21 --
22 regs_m2s : in axi_lite_m2s_t;
23 regs_s2m : out axi_lite_s2m_t := axi_lite_s2m_init;
24 --
25 clock_enable : in std_ulogic;
26 pulse : out std_ulogic := '0'
27 );
28end entity;
29
30architecture a of counter is
31
32 signal regs_up : counter_regs_up_t := counter_regs_up_init;
33 signal regs_down : counter_regs_down_t := counter_regs_down_init;
34
35 signal reg_was_written : counter_reg_was_written_t := counter_reg_was_written_init;
36
37begin
38
39 ------------------------------------------------------------------------------
40 counter_register_file_axi_lite_inst : entity work.counter_register_file_axi_lite
41 port map (
42 clk => clk,
43 --
44 axi_lite_m2s => regs_m2s,
45 axi_lite_s2m => regs_s2m,
46 --
47 regs_up => regs_up,
48 regs_down => regs_down,
49 --
50 reg_was_read => open,
51 reg_was_written => reg_was_written
52 );
53
54
55 ------------------------------------------------------------------------------
56 set_status : process
57 begin
58 wait until rising_edge(clk);
59
60 if regs_down.command.start then
61 regs_up.status.enabled <= '1';
62 end if;
63
64 if regs_down.command.stop then
65 regs_up.status.enabled <= '0';
66 end if;
67
68 if reg_was_written.config then
69 -- Clear value when configuration is changed.
70 regs_up.status.pulse_count <= 0;
71 else
72 regs_up.status.pulse_count <= regs_up.status.pulse_count + to_int(pulse);
73 end if;
74 end process;
75
76
77 ------------------------------------------------------------------------------
78 count_block : block
79 constant counter_width : positive := 10;
80 constant counter_activate_value : positive := 2 ** counter_width - 1;
81 -- One bit extra to avoid overflow.
82 constant counter_max_value : positive := 2 ** (counter_width + 1) - 1;
83
84 signal count : natural range 0 to counter_max_value := 0;
85
86 signal clock_enable_p1 : std_ulogic := '0';
87 begin
88
89 ------------------------------------------------------------------------------
90 count_events : process
91 begin
92 wait until rising_edge(clk);
93
94 pulse <= '0';
95
96 case regs_down.config.condition is
97 when condition_clock_cycles =>
98 count <= count + regs_down.config.increment;
99
100 when condition_clock_cycles_with_enable =>
101 if clock_enable then
102 count <= count + regs_down.config.increment;
103 end if;
104
105 when condition_enable_edges =>
106 if clock_enable /= clock_enable_p1 then
107 count <= count + regs_down.config.increment;
108 end if;
109 end case;
110
111 if count >= counter_activate_value then
112 count <= 0;
113 pulse <= regs_up.status.enabled;
114 end if;
115
116 clock_enable_p1 <= clock_enable;
117 end process;
118
119 end block;
120
121end architecture;
VHDL example testbench
The VHDL below is the testbench for our example counter implementation above.
The testbench uses register read/write procedures from the package produced by
VhdlSimulationReadWritePackageGenerator
, which can be seen below. For examplewrite_counter_config
.The testbench uses register wait until procedures from the package produced by
VhdlSimulationWaitUntilPackageGenerator
, which can be seen below.For example
wait_until_counter_status_pulse_count_equals
, which will continuously read thestatus
register until thepulse_count
field is exactly equal to the supplied value.
The type of the
value
for each procedure is the native record type for that register.For example,
read_counter_status
returns a value of typecounter_status_t
which is a record that contains a bitenabled
and an integerpulse_count
.
The testbench uses register field check procedures from the package produced by
VhdlSimulationCheckPackageGenerator
, which can be seen below. For examplecheck_counter_status_enabled_equal
.The testbench instantiates axi_lite_master.vhd which creates AXI-Lite transactions based on the VUnit bus master verification component interface commands created by the Generated VHDL simulation read/write package.
Click to expand/collapse code.
1library ieee;
2use ieee.std_logic_1164.all;
3
4library vunit_lib;
5use vunit_lib.com_pkg.net;
6use vunit_lib.run_pkg.all;
7
8library axi_lite;
9use axi_lite.axi_lite_pkg.all;
10
11library bfm;
12
13library register_file;
14
15use work.counter_register_record_pkg.all;
16use work.counter_register_check_pkg.all;
17use work.counter_register_read_write_pkg.all;
18use work.counter_register_wait_until_pkg.all;
19use work.counter_regs_pkg.all;
20
21
22entity tb_counter is
23 generic (
24 runner_cfg : string
25 );
26end entity;
27
28architecture tb of tb_counter is
29
30 signal clk : std_ulogic := '0';
31
32 signal regs_m2s : axi_lite_m2s_t := axi_lite_m2s_init;
33 signal regs_s2m : axi_lite_s2m_t := axi_lite_s2m_init;
34
35 signal pulse, clock_enable : std_ulogic := '0';
36
37begin
38
39 clk <= not clk after 5 ns;
40 test_runner_watchdog(runner, 1 ms);
41
42
43 ------------------------------------------------------------------------------
44 main : process
45 variable config : counter_config_t := counter_config_init;
46 begin
47 test_runner_setup(runner, runner_cfg);
48
49 -- Check initial state.
50 check_counter_status_enabled_equal(net=>net, expected=>'0');
51 check_counter_status_pulse_count_equal(net=>net, expected=>0);
52
53 if run("test_count_clock_cycles") then
54 config.condition := condition_clock_cycles;
55 config.increment := 13;
56
57 elsif run("test_count_clock_cycles_with_enable") then
58 config.condition := condition_clock_cycles_with_enable;
59 config.increment := 8;
60
61 clock_enable <= '1';
62 end if;
63
64 -- Set configuration, which depends on test case.
65 write_counter_config(net=>net, value=>config);
66
67 -- Enable the operation.
68 write_counter_command_start(net=>net, value=>'1');
69
70 -- Check updated status.
71 check_counter_status_enabled_equal(net=>net, expected=>'1');
72 check_counter_status_pulse_count_equal(net=>net, expected=>0);
73
74 -- Wait until a number of pulses have passed.
75 wait_until_counter_status_pulse_count_equals(net=>net, value=>10);
76
77 -- Stop the operation.
78 write_counter_command_stop(net=>net, value=>'1');
79
80 -- Make sure that status is updated.
81 check_counter_status_enabled_equal(net=>net, expected=>'0');
82
83 test_runner_cleanup(runner);
84 end process;
85
86
87 ------------------------------------------------------------------------------
88 axi_lite_master_inst : entity bfm.axi_lite_master
89 port map (
90 clk => clk,
91 --
92 axi_lite_m2s => regs_m2s,
93 axi_lite_s2m => regs_s2m
94 );
95
96
97 ------------------------------------------------------------------------------
98 counter_inst : entity work.counter
99 port map (
100 clk => clk,
101 --
102 regs_m2s => regs_m2s,
103 regs_s2m => regs_s2m,
104 --
105 clock_enable => clock_enable,
106 pulse => pulse
107 );
108
109end architecture;
Generated VHDL register package
Below is the generated register package, created from the TOML file above via the
VhdlRegisterPackageGenerator
class.
This is used by the Generated VHDL record package and
the Generated VHDL AXI-Lite register file wrapper.
Click to expand/collapse code.
1-- -----------------------------------------------------------------------------
2-- This file is automatically generated by hdl-registers version 7.0.2-dev.
3-- Code generator VhdlRegisterPackageGenerator version 2.0.0.
4-- Generated 2025-01-21 20:52 from file regs_counter.toml at commit 3c3e6c67d817.
5-- Register hash 49f02a8daa9dd4bc3dadeb2a1cfd61dcc38c3864.
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 counter_regs_pkg is
18
19 -- ---------------------------------------------------------------------------
20 -- The valid range of register indexes.
21 subtype counter_register_range is natural range 0 to 2;
22
23 -- ---------------------------------------------------------------------------
24 -- The number of bits needed to address all 3 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 counter_address_width : positive := 4;
28
29 -- Register indexes, within the list of registers.
30 constant counter_config : natural := 0;
31 constant counter_command : natural := 1;
32 constant counter_status : natural := 2;
33
34 -- Declare 'register_map' and 'regs_init' constants here but define them in
35 -- the package body (deferred constants).
36 -- So that functions have been elaborated when they are called.
37 -- Needed for ModelSim compilation to pass.
38
39 -- To be used as the 'registers' generic of 'axi_lite_register_file.vhd'.
40 constant counter_register_map : register_definition_vec_t(counter_register_range);
41
42 -- To be used for the 'regs_up' and 'regs_down' ports of 'axi_lite_register_file.vhd'.
43 subtype counter_regs_t is register_vec_t(counter_register_range);
44 -- To be used as the 'default_values' generic of 'axi_lite_register_file.vhd'.
45 constant counter_regs_init : counter_regs_t;
46
47 -- To be used for the 'reg_was_read' and 'reg_was_written' ports of 'axi_lite_register_file.vhd'.
48 subtype counter_reg_was_accessed_t is std_ulogic_vector(counter_register_range);
49
50 -- -----------------------------------------------------------------------------
51 -- Fields in the 'config' register.
52 -- Range of the 'condition' field.
53 subtype counter_config_condition is natural range 1 downto 0;
54 -- Width of the 'condition' field.
55 constant counter_config_condition_width : positive := 2;
56 -- Type for the 'condition' field.
57 type counter_config_condition_t is (
58 condition_clock_cycles,
59 condition_clock_cycles_with_enable,
60 condition_enable_edges
61 );
62 -- Default value of the 'condition' field.
63 constant counter_config_condition_init : counter_config_condition_t := condition_clock_cycles;
64 -- Type for the 'condition' field as an SLV.
65 subtype counter_config_condition_slv_t is std_ulogic_vector(1 downto 0);
66 -- Cast a 'condition' field value to SLV.
67 function to_slv(data : counter_config_condition_t) return counter_config_condition_slv_t;
68 -- Get a 'condition' field value from a register value.
69 function to_counter_config_condition(data : register_t) return counter_config_condition_t;
70
71 -- Range of the 'increment' field.
72 subtype counter_config_increment is natural range 5 downto 2;
73 -- Width of the 'increment' field.
74 constant counter_config_increment_width : positive := 4;
75 -- Type for the 'increment' field.
76 subtype counter_config_increment_t is integer range 0 to 15;
77 -- Default value of the 'increment' field.
78 constant counter_config_increment_init : counter_config_increment_t := 0;
79 -- Type for the 'increment' field as an SLV.
80 subtype counter_config_increment_slv_t is std_ulogic_vector(3 downto 0);
81 -- Cast a 'increment' field value to SLV.
82 function to_counter_config_increment_slv(data : counter_config_increment_t) return counter_config_increment_slv_t;
83 -- Get a 'increment' field value from a register value.
84 function to_counter_config_increment(data : register_t) return counter_config_increment_t;
85
86 -- -----------------------------------------------------------------------------
87 -- Fields in the 'command' register.
88 -- Range of the 'start' field.
89 constant counter_command_start : natural := 0;
90 -- Default value of the 'start' field.
91 constant counter_command_start_init : std_ulogic := '0';
92
93 -- Range of the 'stop' field.
94 constant counter_command_stop : natural := 1;
95 -- Default value of the 'stop' field.
96 constant counter_command_stop_init : std_ulogic := '0';
97
98 -- -----------------------------------------------------------------------------
99 -- Fields in the 'status' register.
100 -- Range of the 'enabled' field.
101 constant counter_status_enabled : natural := 0;
102 -- Default value of the 'enabled' field.
103 constant counter_status_enabled_init : std_ulogic := '0';
104
105 -- Range of the 'pulse_count' field.
106 subtype counter_status_pulse_count is natural range 8 downto 1;
107 -- Width of the 'pulse_count' field.
108 constant counter_status_pulse_count_width : positive := 8;
109 -- Type for the 'pulse_count' field.
110 subtype counter_status_pulse_count_t is integer range 0 to 255;
111 -- Default value of the 'pulse_count' field.
112 constant counter_status_pulse_count_init : counter_status_pulse_count_t := 0;
113 -- Type for the 'pulse_count' field as an SLV.
114 subtype counter_status_pulse_count_slv_t is std_ulogic_vector(7 downto 0);
115 -- Cast a 'pulse_count' field value to SLV.
116 function to_counter_status_pulse_count_slv(data : counter_status_pulse_count_t) return counter_status_pulse_count_slv_t;
117 -- Get a 'pulse_count' field value from a register value.
118 function to_counter_status_pulse_count(data : register_t) return counter_status_pulse_count_t;
119
120end package;
121
122package body counter_regs_pkg is
123
124 constant counter_register_map : register_definition_vec_t(counter_register_range) := (
125 0 => (index => counter_config, mode => r_w, utilized_width => 6),
126 1 => (index => counter_command, mode => wpulse, utilized_width => 2),
127 2 => (index => counter_status, mode => r, utilized_width => 9)
128 );
129
130 constant counter_regs_init : counter_regs_t := (
131 0 => "00000000000000000000000000000000",
132 1 => "00000000000000000000000000000000",
133 2 => "00000000000000000000000000000000"
134 );
135
136 -- Cast a 'condition' field value to SLV.
137 function to_slv(data : counter_config_condition_t) return counter_config_condition_slv_t is
138 constant data_int : natural := counter_config_condition_t'pos(data);
139 constant result : counter_config_condition_slv_t := std_ulogic_vector(
140 to_unsigned(data_int, counter_config_condition_width)
141 );
142 begin
143 return result;
144 end function;
145
146 -- Get a 'condition' field value from a register value.
147 function to_counter_config_condition(data : register_t) return counter_config_condition_t is
148 constant field_slv : counter_config_condition_slv_t := data(counter_config_condition);
149 constant field_int : natural := to_integer(unsigned(field_slv));
150 constant result : counter_config_condition_t := counter_config_condition_t'val(field_int);
151 begin
152 return result;
153 end function;
154
155 -- Cast a 'increment' field value to SLV.
156 function to_counter_config_increment_slv(data : counter_config_increment_t) return counter_config_increment_slv_t is
157 constant result : counter_config_increment_slv_t := std_ulogic_vector(to_unsigned(data, counter_config_increment_width));
158 begin
159 return result;
160 end function;
161
162 -- Get a 'increment' field value from a register value.
163 function to_counter_config_increment(data : register_t) return counter_config_increment_t is
164 constant result : integer := to_integer(unsigned(data(counter_config_increment)));
165 begin
166 return result;
167 end function;
168
169 -- Cast a 'pulse_count' field value to SLV.
170 function to_counter_status_pulse_count_slv(data : counter_status_pulse_count_t) return counter_status_pulse_count_slv_t is
171 constant result : counter_status_pulse_count_slv_t := std_ulogic_vector(to_unsigned(data, counter_status_pulse_count_width));
172 begin
173 return result;
174 end function;
175
176 -- Get a 'pulse_count' field value from a register value.
177 function to_counter_status_pulse_count(data : register_t) return counter_status_pulse_count_t is
178 constant result : integer := to_integer(unsigned(data(counter_status_pulse_count)));
179 begin
180 return result;
181 end function;
182
183end package body;
Generated VHDL record package
Below is the generated record package, created from the TOML file above via the
VhdlRecordPackageGenerator
class.
This is used by the Generated VHDL AXI-Lite register file wrapper as well as the
VHDL example implementation and the VHDL example testbench.
Click to expand/collapse code.
1-- -----------------------------------------------------------------------------
2-- This file is automatically generated by hdl-registers version 7.0.2-dev.
3-- Code generator VhdlRecordPackageGenerator version 1.0.0.
4-- Generated 2025-01-21 20:52 from file regs_counter.toml at commit 3c3e6c67d817.
5-- Register hash 49f02a8daa9dd4bc3dadeb2a1cfd61dcc38c3864.
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.counter_regs_pkg.all;
17
18
19package counter_register_record_pkg is
20
21 -- -----------------------------------------------------------------------------
22 -- Record with correctly-typed members for each field in each register.
23 -- Fields in the 'config' register as a record.
24 type counter_config_t is record
25 condition : counter_config_condition_t;
26 increment : counter_config_increment_t;
27 end record;
28 -- Default value for the 'config' register as a record.
29 constant counter_config_init : counter_config_t := (
30 condition => counter_config_condition_init,
31 increment => counter_config_increment_init
32 );
33 -- Convert a record of the 'config' register to SLV.
34 function to_slv(data : counter_config_t) return register_t;
35 -- Convert an SLV register value to the record for the 'config' register.
36 function to_counter_config(data : register_t) return counter_config_t;
37
38 -- Fields in the 'command' register as a record.
39 type counter_command_t is record
40 start : std_ulogic;
41 stop : std_ulogic;
42 end record;
43 -- Default value for the 'command' register as a record.
44 constant counter_command_init : counter_command_t := (
45 start => counter_command_start_init,
46 stop => counter_command_stop_init
47 );
48 -- Convert a record of the 'command' register to SLV.
49 function to_slv(data : counter_command_t) return register_t;
50 -- Convert an SLV register value to the record for the 'command' register.
51 function to_counter_command(data : register_t) return counter_command_t;
52
53 -- Fields in the 'status' register as a record.
54 type counter_status_t is record
55 enabled : std_ulogic;
56 pulse_count : counter_status_pulse_count_t;
57 end record;
58 -- Default value for the 'status' register as a record.
59 constant counter_status_init : counter_status_t := (
60 enabled => counter_status_enabled_init,
61 pulse_count => counter_status_pulse_count_init
62 );
63 -- Convert a record of the 'status' register to SLV.
64 function to_slv(data : counter_status_t) return register_t;
65 -- Convert an SLV register value to the record for the 'status' register.
66 function to_counter_status(data : register_t) return counter_status_t;
67
68 -- -----------------------------------------------------------------------------
69 -- Below is a record with correctly typed and ranged members for all registers, register arrays
70 -- and fields that are in the 'up' direction.
71 -- Record with everything in the 'up' direction.
72 type counter_regs_up_t is record
73 status : counter_status_t;
74 end record;
75 -- Default value of the above record.
76 constant counter_regs_up_init : counter_regs_up_t := (
77 status => counter_status_init
78 );
79 -- Convert record with everything in the 'up' direction to SLV register list.
80 function to_slv(data : counter_regs_up_t) return counter_regs_t;
81
82 -- -----------------------------------------------------------------------------
83 -- Below is a record with correctly typed and ranged members for all registers, register arrays
84 -- and fields that are in the 'down' direction.
85 -- Record with everything in the 'down' direction.
86 type counter_regs_down_t is record
87 config : counter_config_t;
88 command : counter_command_t;
89 end record;
90 -- Default value of the above record.
91 constant counter_regs_down_init : counter_regs_down_t := (
92 config => counter_config_init,
93 command => counter_command_init
94 );
95 -- Convert SLV register list to record with everything in the 'down' direction.
96 function to_counter_regs_down(data : counter_regs_t) return counter_regs_down_t;
97
98 -- ---------------------------------------------------------------------------
99 -- Below is a record with a status bit for each readable register in the register list.
100 -- It can be used for the 'reg_was_read' port of a register file wrapper.
101 -- Combined status mask record for all readable register.
102 type counter_reg_was_read_t is record
103 config : std_ulogic;
104 status : std_ulogic;
105 end record;
106 -- Default value for the above record.
107 constant counter_reg_was_read_init : counter_reg_was_read_t := (
108 others => '0'
109 );
110 -- Convert an SLV 'reg_was_read' from generic register file to the record above.
111 function to_counter_reg_was_read(
112 data : counter_reg_was_accessed_t
113 ) return counter_reg_was_read_t;
114
115 -- ---------------------------------------------------------------------------
116 -- Below is a record with a status bit for each writeable register in the register list.
117 -- It can be used for the 'reg_was_written' port of a register file wrapper.
118 -- Combined status mask record for all writeable register.
119 type counter_reg_was_written_t is record
120 config : std_ulogic;
121 command : std_ulogic;
122 end record;
123 -- Default value for the above record.
124 constant counter_reg_was_written_init : counter_reg_was_written_t := (
125 others => '0'
126 );
127 -- Convert an SLV 'reg_was_written' from generic register file to the record above.
128 function to_counter_reg_was_written(
129 data : counter_reg_was_accessed_t
130 ) return counter_reg_was_written_t;
131
132end package;
133
134package body counter_register_record_pkg is
135
136 function to_slv(data : counter_config_t) return register_t is
137 variable result : register_t := (others => '-');
138 begin
139 result(counter_config_condition) := to_slv(data.condition);
140 result(counter_config_increment) := to_counter_config_increment_slv(data.increment);
141
142 return result;
143 end function;
144
145 function to_counter_config(data : register_t) return counter_config_t is
146 variable result : counter_config_t := counter_config_init;
147 begin
148 result.condition := to_counter_config_condition(data);
149 result.increment := to_counter_config_increment(data);
150
151 return result;
152 end function;
153
154 function to_slv(data : counter_command_t) return register_t is
155 variable result : register_t := (others => '-');
156 begin
157 result(counter_command_start) := data.start;
158 result(counter_command_stop) := data.stop;
159
160 return result;
161 end function;
162
163 function to_counter_command(data : register_t) return counter_command_t is
164 variable result : counter_command_t := counter_command_init;
165 begin
166 result.start := data(counter_command_start);
167 result.stop := data(counter_command_stop);
168
169 return result;
170 end function;
171
172 function to_slv(data : counter_status_t) return register_t is
173 variable result : register_t := (others => '-');
174 begin
175 result(counter_status_enabled) := data.enabled;
176 result(counter_status_pulse_count) := to_counter_status_pulse_count_slv(data.pulse_count);
177
178 return result;
179 end function;
180
181 function to_counter_status(data : register_t) return counter_status_t is
182 variable result : counter_status_t := counter_status_init;
183 begin
184 result.enabled := data(counter_status_enabled);
185 result.pulse_count := to_counter_status_pulse_count(data);
186
187 return result;
188 end function;
189
190 function to_slv(data : counter_regs_up_t) return counter_regs_t is
191 variable result : counter_regs_t := counter_regs_init;
192 begin
193 result(counter_status) := to_slv(data.status);
194
195 return result;
196 end function;
197
198 function to_counter_regs_down(data : counter_regs_t) return counter_regs_down_t is
199 variable result : counter_regs_down_t := counter_regs_down_init;
200 begin
201 result.config := to_counter_config(data(counter_config));
202 result.command := to_counter_command(data(counter_command));
203
204 return result;
205 end function;
206
207 function to_counter_reg_was_read(
208 data : counter_reg_was_accessed_t
209 ) return counter_reg_was_read_t is
210 variable result : counter_reg_was_read_t := counter_reg_was_read_init;
211 begin
212 result.config := data(counter_config);
213 result.status := data(counter_status);
214
215 return result;
216 end function;
217
218 function to_counter_reg_was_written(
219 data : counter_reg_was_accessed_t
220 ) return counter_reg_was_written_t is
221 variable result : counter_reg_was_written_t := counter_reg_was_written_init;
222 begin
223 result.config := data(counter_config);
224 result.command := data(counter_command);
225
226 return result;
227 end function;
228
229end package body;
Generated VHDL AXI-Lite register file wrapper
Below is the generated AXI-Lite register file wrapper, created from the TOML file above via the
VhdlAxiLiteWrapperGenerator
class.
This is instantiated in the VHDL example implementation to get register values of native type
without any manual casting.
Click to expand/collapse code.
1-- -----------------------------------------------------------------------------
2-- This file is automatically generated by hdl-registers version 7.0.2-dev.
3-- Code generator VhdlAxiLiteWrapperGenerator version 1.0.0.
4-- Generated 2025-01-21 20:52 from file regs_counter.toml at commit 3c3e6c67d817.
5-- Register hash 49f02a8daa9dd4bc3dadeb2a1cfd61dcc38c3864.
6-- -----------------------------------------------------------------------------
7
8-- -----------------------------------------------------------------------------
9-- AXI-Lite register file for the 'counter' module registers.
10--
11-- Is a wrapper around the generic AXI-Lite register file from hdl-modules:
12-- * https://hdl-modules.com/modules/register_file/register_file.html#axi-lite-reg-file-vhd
13-- * https://github.com/hdl-modules/hdl-modules/blob/main/modules/register_file/src/axi_lite_register_file.vhd
14--
15-- Sets correct generics, and performs conversion to the easy-to-use register record types.
16-- -----------------------------------------------------------------------------
17
18library ieee;
19use ieee.std_logic_1164.all;
20
21library axi_lite;
22use axi_lite.axi_lite_pkg.all;
23
24library register_file;
25use register_file.register_file_pkg.all;
26
27use work.counter_regs_pkg.all;
28use work.counter_register_record_pkg.all;
29
30
31entity counter_register_file_axi_lite is
32 port (
33 clk : in std_ulogic;
34 --# {}
35 --# Register control bus.
36 axi_lite_m2s : in axi_lite_m2s_t;
37 axi_lite_s2m : out axi_lite_s2m_t := axi_lite_s2m_init;
38 --# {}
39 -- Register values.
40 regs_up : in counter_regs_up_t := counter_regs_up_init;
41 regs_down : out counter_regs_down_t := counter_regs_down_init;
42 --# {}
43 -- Each bit is pulsed for one cycle when the corresponding register is read/written.
44 reg_was_read : out counter_reg_was_read_t := counter_reg_was_read_init;
45 reg_was_written : out counter_reg_was_written_t := counter_reg_was_written_init
46 );
47end entity;
48
49architecture a of counter_register_file_axi_lite is
50
51 signal regs_up_slv, regs_down_slv : counter_regs_t := counter_regs_init;
52
53 signal reg_was_read_slv, reg_was_written_slv : counter_reg_was_accessed_t := (
54 others => '0'
55 );
56
57begin
58
59 ------------------------------------------------------------------------------
60 -- Instantiate the generic AXI-Lite register file from
61 -- * https://hdl-modules.com/modules/register_file/register_file.html#axi-lite-reg-file-vhd
62 -- * https://github.com/hdl-modules/hdl-modules/blob/main/modules/register_file/src/axi_lite_register_file.vhd
63 axi_lite_register_file_inst : entity register_file.axi_lite_register_file
64 generic map (
65 registers => counter_register_map,
66 default_values => counter_regs_init
67 )
68 port map(
69 clk => clk,
70 --
71 axi_lite_m2s => axi_lite_m2s,
72 axi_lite_s2m => axi_lite_s2m,
73 --
74 regs_up => regs_up_slv,
75 regs_down => regs_down_slv,
76 --
77 reg_was_read => reg_was_read_slv,
78 reg_was_written => reg_was_written_slv
79 );
80
81
82 ------------------------------------------------------------------------------
83 -- Combinatorially convert the register record to a list of SLV values that can be handled
84 -- by the generic register file implementation.
85 assign_regs_up : process(regs_up)
86 begin
87 regs_up_slv <= to_slv(regs_up);
88 end process;
89
90
91 ------------------------------------------------------------------------------
92 -- Combinatorially convert the list of SLV values from the generic register file into the record
93 -- we want to use in our application.
94 assign_regs_down : process(regs_down_slv)
95 begin
96 regs_down <= to_counter_regs_down(regs_down_slv);
97 end process;
98
99
100 ------------------------------------------------------------------------------
101 -- Combinatorially convert status mask to a record where only the applicable registers are present.
102 assign_reg_was_read : process(reg_was_read_slv)
103 begin
104 reg_was_read <= to_counter_reg_was_read(reg_was_read_slv);
105 end process;
106
107
108 ------------------------------------------------------------------------------
109 -- Combinatorially convert status mask to a record where only the applicable registers are present.
110 assign_reg_was_written : process(reg_was_written_slv)
111 begin
112 reg_was_written <= to_counter_reg_was_written(reg_was_written_slv);
113 end process;
114
115end architecture;
Generated VHDL simulation read/write package
Below is the generated register simulation read/write package, created from the TOML file above via
the VhdlSimulationReadWritePackageGenerator
class.
It is used by the VHDL example testbench to read/write registers in a compact way.
Click to expand/collapse code.
1-- -----------------------------------------------------------------------------
2-- This file is automatically generated by hdl-registers version 7.0.2-dev.
3-- Code generator VhdlSimulationReadWritePackageGenerator version 1.1.0.
4-- Generated 2025-01-21 20:52 from file regs_counter.toml at commit 3c3e6c67d817.
5-- Register hash 49f02a8daa9dd4bc3dadeb2a1cfd61dcc38c3864.
6-- -----------------------------------------------------------------------------
7
8library ieee;
9use ieee.numeric_std.all;
10use ieee.std_logic_1164.all;
11
12library vunit_lib;
13use vunit_lib.bus_master_pkg.bus_master_t;
14use vunit_lib.bus_master_pkg.read_bus;
15use vunit_lib.bus_master_pkg.write_bus;
16use vunit_lib.com_types_pkg.network_t;
17
18library common;
19use common.addr_pkg.addr_t;
20use common.addr_pkg.addr_width;
21
22library register_file;
23use register_file.register_file_pkg.register_t;
24use register_file.register_file_pkg.register_width;
25use register_file.register_operations_pkg.register_bus_master;
26
27use work.counter_regs_pkg.all;
28use work.counter_register_record_pkg.all;
29
30
31package counter_register_read_write_pkg is
32
33 -- ---------------------------------------------------------------------------
34 -- Read the 'config' register as a plain 'register_t'.
35 procedure read_counter_config(
36 signal net : inout network_t;
37 value : out register_t;
38 base_address : in addr_t := (others => '0');
39 bus_handle : in bus_master_t := register_bus_master
40 );
41
42 -- Read the 'config' register as an 'integer'.
43 procedure read_counter_config(
44 signal net : inout network_t;
45 value : out integer;
46 base_address : in addr_t := (others => '0');
47 bus_handle : in bus_master_t := register_bus_master
48 );
49
50 -- Read the 'config' register.
51 procedure read_counter_config(
52 signal net : inout network_t;
53 value : out counter_config_t;
54 base_address : in addr_t := (others => '0');
55 bus_handle : in bus_master_t := register_bus_master
56 );
57
58 -- Read the 'condition' field in the 'config' register.
59 procedure read_counter_config_condition(
60 signal net : inout network_t;
61 value : out counter_config_condition_t;
62 base_address : in addr_t := (others => '0');
63 bus_handle : in bus_master_t := register_bus_master
64 );
65
66 -- Read the 'increment' field in the 'config' register.
67 procedure read_counter_config_increment(
68 signal net : inout network_t;
69 value : out counter_config_increment_t;
70 base_address : in addr_t := (others => '0');
71 bus_handle : in bus_master_t := register_bus_master
72 );
73
74 -- Write the 'config' register as an 'integer'.
75 procedure write_counter_config(
76 signal net : inout network_t;
77 value : in integer;
78 base_address : in addr_t := (others => '0');
79 bus_handle : in bus_master_t := register_bus_master
80 );
81
82 -- Write the 'config' register.
83 procedure write_counter_config(
84 signal net : inout network_t;
85 value : in counter_config_t;
86 base_address : in addr_t := (others => '0');
87 bus_handle : in bus_master_t := register_bus_master
88 );
89
90 -- Write the 'condition' field in the 'config' register.
91 -- Will read-modify-write the register to set the field to the supplied 'value'.
92 procedure write_counter_config_condition(
93 signal net : inout network_t;
94 value : in counter_config_condition_t;
95 base_address : in addr_t := (others => '0');
96 bus_handle : in bus_master_t := register_bus_master
97 );
98
99 -- Write the 'increment' field in the 'config' register.
100 -- Will read-modify-write the register to set the field to the supplied 'value'.
101 procedure write_counter_config_increment(
102 signal net : inout network_t;
103 value : in counter_config_increment_t;
104 base_address : in addr_t := (others => '0');
105 bus_handle : in bus_master_t := register_bus_master
106 );
107 -- ---------------------------------------------------------------------------
108
109 -- ---------------------------------------------------------------------------
110 -- Write the 'command' register as an 'integer'.
111 procedure write_counter_command(
112 signal net : inout network_t;
113 value : in integer;
114 base_address : in addr_t := (others => '0');
115 bus_handle : in bus_master_t := register_bus_master
116 );
117
118 -- Write the 'command' register.
119 procedure write_counter_command(
120 signal net : inout network_t;
121 value : in counter_command_t;
122 base_address : in addr_t := (others => '0');
123 bus_handle : in bus_master_t := register_bus_master
124 );
125
126 -- Write the 'start' field in the 'command' register.
127 -- Will write the whole register, with the field set to the
128 -- supplied 'value' and everything else set to default.
129 procedure write_counter_command_start(
130 signal net : inout network_t;
131 value : in std_ulogic;
132 base_address : in addr_t := (others => '0');
133 bus_handle : in bus_master_t := register_bus_master
134 );
135
136 -- Write the 'stop' field in the 'command' register.
137 -- Will write the whole register, with the field set to the
138 -- supplied 'value' and everything else set to default.
139 procedure write_counter_command_stop(
140 signal net : inout network_t;
141 value : in std_ulogic;
142 base_address : in addr_t := (others => '0');
143 bus_handle : in bus_master_t := register_bus_master
144 );
145 -- ---------------------------------------------------------------------------
146
147 -- ---------------------------------------------------------------------------
148 -- Read the 'status' register as a plain 'register_t'.
149 procedure read_counter_status(
150 signal net : inout network_t;
151 value : out register_t;
152 base_address : in addr_t := (others => '0');
153 bus_handle : in bus_master_t := register_bus_master
154 );
155
156 -- Read the 'status' register as an 'integer'.
157 procedure read_counter_status(
158 signal net : inout network_t;
159 value : out integer;
160 base_address : in addr_t := (others => '0');
161 bus_handle : in bus_master_t := register_bus_master
162 );
163
164 -- Read the 'status' register.
165 procedure read_counter_status(
166 signal net : inout network_t;
167 value : out counter_status_t;
168 base_address : in addr_t := (others => '0');
169 bus_handle : in bus_master_t := register_bus_master
170 );
171
172 -- Read the 'enabled' field in the 'status' register.
173 procedure read_counter_status_enabled(
174 signal net : inout network_t;
175 value : out std_ulogic;
176 base_address : in addr_t := (others => '0');
177 bus_handle : in bus_master_t := register_bus_master
178 );
179
180 -- Read the 'pulse_count' field in the 'status' register.
181 procedure read_counter_status_pulse_count(
182 signal net : inout network_t;
183 value : out counter_status_pulse_count_t;
184 base_address : in addr_t := (others => '0');
185 bus_handle : in bus_master_t := register_bus_master
186 );
187 -- ---------------------------------------------------------------------------
188
189end package;
190
191package body counter_register_read_write_pkg is
192
193 -- ---------------------------------------------------------------------------
194 -- Read the 'config' register as a plain 'register_t'.
195 procedure read_counter_config(
196 signal net : inout network_t;
197 value : out register_t;
198 base_address : in addr_t := (others => '0');
199 bus_handle : in bus_master_t := register_bus_master
200 ) is
201 constant reg_index : counter_register_range := counter_config;
202 constant reg_address : addr_t := base_address + to_unsigned(4 * reg_index, addr_width);
203 variable reg_value : register_t := (others => '0');
204 begin
205 read_bus(
206 net => net,
207 bus_handle => bus_handle,
208 address => std_logic_vector(reg_address),
209 data => reg_value
210 );
211 value := reg_value;
212 end procedure;
213
214 -- Read the 'config' register as an 'integer'.
215 procedure read_counter_config(
216 signal net : inout network_t;
217 value : out integer;
218 base_address : in addr_t := (others => '0');
219 bus_handle : in bus_master_t := register_bus_master
220 ) is
221 constant reg_index : counter_register_range := counter_config;
222 constant reg_address : addr_t := base_address + to_unsigned(4 * reg_index, addr_width);
223 variable reg_value : register_t := (others => '0');
224 begin
225 read_bus(
226 net => net,
227 bus_handle => bus_handle,
228 address => std_logic_vector(reg_address),
229 data => reg_value
230 );
231 value := to_integer(unsigned(reg_value));
232 end procedure;
233
234 -- Read the 'config' register.
235 procedure read_counter_config(
236 signal net : inout network_t;
237 value : out counter_config_t;
238 base_address : in addr_t := (others => '0');
239 bus_handle : in bus_master_t := register_bus_master
240 ) is
241 constant reg_index : counter_register_range := counter_config;
242 constant reg_address : addr_t := base_address + to_unsigned(4 * reg_index, addr_width);
243 variable reg_value : register_t := (others => '0');
244 begin
245 read_bus(
246 net => net,
247 bus_handle => bus_handle,
248 address => std_logic_vector(reg_address),
249 data => reg_value
250 );
251 value := to_counter_config(reg_value);
252 end procedure;
253
254 -- Read the 'condition' field in the 'config' register.
255 procedure read_counter_config_condition(
256 signal net : inout network_t;
257 value : out counter_config_condition_t;
258 base_address : in addr_t := (others => '0');
259 bus_handle : in bus_master_t := register_bus_master
260 ) is
261 variable reg_value : counter_config_t := counter_config_init;
262 begin
263 read_counter_config(
264 net => net,
265 value => reg_value,
266 base_address => base_address,
267 bus_handle => bus_handle
268 );
269 value := reg_value.condition;
270 end procedure;
271
272 -- Read the 'increment' field in the 'config' register.
273 procedure read_counter_config_increment(
274 signal net : inout network_t;
275 value : out counter_config_increment_t;
276 base_address : in addr_t := (others => '0');
277 bus_handle : in bus_master_t := register_bus_master
278 ) is
279 variable reg_value : counter_config_t := counter_config_init;
280 begin
281 read_counter_config(
282 net => net,
283 value => reg_value,
284 base_address => base_address,
285 bus_handle => bus_handle
286 );
287 value := reg_value.increment;
288 end procedure;
289
290 -- Write the 'config' register as an 'integer'.
291 procedure write_counter_config(
292 signal net : inout network_t;
293 value : in integer;
294 base_address : in addr_t := (others => '0');
295 bus_handle : in bus_master_t := register_bus_master
296 ) is
297 constant reg_index : counter_register_range := counter_config;
298 constant reg_address : addr_t := base_address + to_unsigned(4 * reg_index, addr_width);
299 constant reg_value : register_t := std_ulogic_vector(to_unsigned(value, register_width));
300 begin
301 write_bus(
302 net => net,
303 bus_handle => bus_handle,
304 address => std_logic_vector(reg_address),
305 data => reg_value
306 );
307 end procedure;
308
309 -- Write the 'config' register.
310 procedure write_counter_config(
311 signal net : inout network_t;
312 value : in counter_config_t;
313 base_address : in addr_t := (others => '0');
314 bus_handle : in bus_master_t := register_bus_master
315 ) is
316 constant reg_index : counter_register_range := counter_config;
317 constant reg_address : addr_t := base_address + to_unsigned(4 * reg_index, addr_width);
318 constant reg_value : register_t := to_slv(value);
319 begin
320 write_bus(
321 net => net,
322 bus_handle => bus_handle,
323 address => std_logic_vector(reg_address),
324 data => reg_value
325 );
326 end procedure;
327
328 -- Write the 'condition' field in the 'config' register.
329 -- Will read-modify-write the register to set the field to the supplied 'value'.
330 procedure write_counter_config_condition(
331 signal net : inout network_t;
332 value : in counter_config_condition_t;
333 base_address : in addr_t := (others => '0');
334 bus_handle : in bus_master_t := register_bus_master
335 ) is
336 variable reg_value : counter_config_t := counter_config_init;
337 begin
338 read_counter_config(
339 net => net,
340 value => reg_value,
341 base_address => base_address,
342 bus_handle => bus_handle
343 );
344 reg_value.condition := value;
345
346 write_counter_config(
347 net => net,
348 value => reg_value,
349 base_address => base_address,
350 bus_handle => bus_handle
351 );
352 end procedure;
353
354 -- Write the 'increment' field in the 'config' register.
355 -- Will read-modify-write the register to set the field to the supplied 'value'.
356 procedure write_counter_config_increment(
357 signal net : inout network_t;
358 value : in counter_config_increment_t;
359 base_address : in addr_t := (others => '0');
360 bus_handle : in bus_master_t := register_bus_master
361 ) is
362 variable reg_value : counter_config_t := counter_config_init;
363 begin
364 read_counter_config(
365 net => net,
366 value => reg_value,
367 base_address => base_address,
368 bus_handle => bus_handle
369 );
370 reg_value.increment := value;
371
372 write_counter_config(
373 net => net,
374 value => reg_value,
375 base_address => base_address,
376 bus_handle => bus_handle
377 );
378 end procedure;
379 -- ---------------------------------------------------------------------------
380
381 -- ---------------------------------------------------------------------------
382 -- Write the 'command' register as an 'integer'.
383 procedure write_counter_command(
384 signal net : inout network_t;
385 value : in integer;
386 base_address : in addr_t := (others => '0');
387 bus_handle : in bus_master_t := register_bus_master
388 ) is
389 constant reg_index : counter_register_range := counter_command;
390 constant reg_address : addr_t := base_address + to_unsigned(4 * reg_index, addr_width);
391 constant reg_value : register_t := std_ulogic_vector(to_unsigned(value, register_width));
392 begin
393 write_bus(
394 net => net,
395 bus_handle => bus_handle,
396 address => std_logic_vector(reg_address),
397 data => reg_value
398 );
399 end procedure;
400
401 -- Write the 'command' register.
402 procedure write_counter_command(
403 signal net : inout network_t;
404 value : in counter_command_t;
405 base_address : in addr_t := (others => '0');
406 bus_handle : in bus_master_t := register_bus_master
407 ) is
408 constant reg_index : counter_register_range := counter_command;
409 constant reg_address : addr_t := base_address + to_unsigned(4 * reg_index, addr_width);
410 constant reg_value : register_t := to_slv(value);
411 begin
412 write_bus(
413 net => net,
414 bus_handle => bus_handle,
415 address => std_logic_vector(reg_address),
416 data => reg_value
417 );
418 end procedure;
419
420 -- Write the 'start' field in the 'command' register.
421 -- Will write the whole register, with the field set to the
422 -- supplied 'value' and everything else set to default.
423 procedure write_counter_command_start(
424 signal net : inout network_t;
425 value : in std_ulogic;
426 base_address : in addr_t := (others => '0');
427 bus_handle : in bus_master_t := register_bus_master
428 ) is
429 variable reg_value : counter_command_t := counter_command_init;
430 begin
431 reg_value.start := value;
432
433 write_counter_command(
434 net => net,
435 value => reg_value,
436 base_address => base_address,
437 bus_handle => bus_handle
438 );
439 end procedure;
440
441 -- Write the 'stop' field in the 'command' register.
442 -- Will write the whole register, with the field set to the
443 -- supplied 'value' and everything else set to default.
444 procedure write_counter_command_stop(
445 signal net : inout network_t;
446 value : in std_ulogic;
447 base_address : in addr_t := (others => '0');
448 bus_handle : in bus_master_t := register_bus_master
449 ) is
450 variable reg_value : counter_command_t := counter_command_init;
451 begin
452 reg_value.stop := value;
453
454 write_counter_command(
455 net => net,
456 value => reg_value,
457 base_address => base_address,
458 bus_handle => bus_handle
459 );
460 end procedure;
461 -- ---------------------------------------------------------------------------
462
463 -- ---------------------------------------------------------------------------
464 -- Read the 'status' register as a plain 'register_t'.
465 procedure read_counter_status(
466 signal net : inout network_t;
467 value : out register_t;
468 base_address : in addr_t := (others => '0');
469 bus_handle : in bus_master_t := register_bus_master
470 ) is
471 constant reg_index : counter_register_range := counter_status;
472 constant reg_address : addr_t := base_address + to_unsigned(4 * reg_index, addr_width);
473 variable reg_value : register_t := (others => '0');
474 begin
475 read_bus(
476 net => net,
477 bus_handle => bus_handle,
478 address => std_logic_vector(reg_address),
479 data => reg_value
480 );
481 value := reg_value;
482 end procedure;
483
484 -- Read the 'status' register as an 'integer'.
485 procedure read_counter_status(
486 signal net : inout network_t;
487 value : out integer;
488 base_address : in addr_t := (others => '0');
489 bus_handle : in bus_master_t := register_bus_master
490 ) is
491 constant reg_index : counter_register_range := counter_status;
492 constant reg_address : addr_t := base_address + to_unsigned(4 * reg_index, addr_width);
493 variable reg_value : register_t := (others => '0');
494 begin
495 read_bus(
496 net => net,
497 bus_handle => bus_handle,
498 address => std_logic_vector(reg_address),
499 data => reg_value
500 );
501 value := to_integer(unsigned(reg_value));
502 end procedure;
503
504 -- Read the 'status' register.
505 procedure read_counter_status(
506 signal net : inout network_t;
507 value : out counter_status_t;
508 base_address : in addr_t := (others => '0');
509 bus_handle : in bus_master_t := register_bus_master
510 ) is
511 constant reg_index : counter_register_range := counter_status;
512 constant reg_address : addr_t := base_address + to_unsigned(4 * reg_index, addr_width);
513 variable reg_value : register_t := (others => '0');
514 begin
515 read_bus(
516 net => net,
517 bus_handle => bus_handle,
518 address => std_logic_vector(reg_address),
519 data => reg_value
520 );
521 value := to_counter_status(reg_value);
522 end procedure;
523
524 -- Read the 'enabled' field in the 'status' register.
525 procedure read_counter_status_enabled(
526 signal net : inout network_t;
527 value : out std_ulogic;
528 base_address : in addr_t := (others => '0');
529 bus_handle : in bus_master_t := register_bus_master
530 ) is
531 variable reg_value : counter_status_t := counter_status_init;
532 begin
533 read_counter_status(
534 net => net,
535 value => reg_value,
536 base_address => base_address,
537 bus_handle => bus_handle
538 );
539 value := reg_value.enabled;
540 end procedure;
541
542 -- Read the 'pulse_count' field in the 'status' register.
543 procedure read_counter_status_pulse_count(
544 signal net : inout network_t;
545 value : out counter_status_pulse_count_t;
546 base_address : in addr_t := (others => '0');
547 bus_handle : in bus_master_t := register_bus_master
548 ) is
549 variable reg_value : counter_status_t := counter_status_init;
550 begin
551 read_counter_status(
552 net => net,
553 value => reg_value,
554 base_address => base_address,
555 bus_handle => bus_handle
556 );
557 value := reg_value.pulse_count;
558 end procedure;
559 -- ---------------------------------------------------------------------------
560
561end package body;
Generated VHDL simulation check package
Below is the generated register simulation check package, created from the TOML file above via
the VhdlSimulationCheckPackageGenerator
class.
It is used by the VHDL example testbench to check that the status
register has the
expected value.
Click to expand/collapse code.
1-- -----------------------------------------------------------------------------
2-- This file is automatically generated by hdl-registers version 7.0.2-dev.
3-- Code generator VhdlSimulationCheckPackageGenerator version 1.2.0.
4-- Generated 2025-01-21 20:52 from file regs_counter.toml at commit 3c3e6c67d817.
5-- Register hash 49f02a8daa9dd4bc3dadeb2a1cfd61dcc38c3864.
6-- -----------------------------------------------------------------------------
7
8library ieee;
9use ieee.fixed_pkg.all;
10use ieee.numeric_std.all;
11use ieee.std_logic_1164.all;
12
13library vunit_lib;
14use vunit_lib.bus_master_pkg.bus_master_t;
15use vunit_lib.check_pkg.all;
16use vunit_lib.checker_pkg.all;
17use vunit_lib.com_types_pkg.network_t;
18use vunit_lib.string_ops.hex_image;
19
20library common;
21use common.addr_pkg.addr_t;
22
23library register_file;
24use register_file.register_file_pkg.register_t;
25use register_file.register_operations_pkg.register_bus_master;
26
27use work.counter_register_read_write_pkg.all;
28use work.counter_register_record_pkg.all;
29use work.counter_regs_pkg.all;
30
31
32package counter_register_check_pkg is
33
34 -- ---------------------------------------------------------------------------
35 -- Check that the current value of the 'config' register
36 -- equals the given 'expected' value as a plain SLV casted to integer.
37 procedure check_counter_config_equal(
38 signal net : inout network_t;
39 expected : in integer;
40 base_address : in addr_t := (others => '0');
41 bus_handle : in bus_master_t := register_bus_master;
42 message : in string := ""
43 );
44
45 -- Check that the current value of the 'config' register
46 -- equals the given 'expected' value.
47 procedure check_counter_config_equal(
48 signal net : inout network_t;
49 expected : in counter_config_t;
50 base_address : in addr_t := (others => '0');
51 bus_handle : in bus_master_t := register_bus_master;
52 message : in string := ""
53 );
54
55 -- Check that the current value of the 'condition' field in the 'config' register
56 -- equals the given 'expected' value.
57 procedure check_counter_config_condition_equal(
58 signal net : inout network_t;
59 expected : in counter_config_condition_t;
60 base_address : in addr_t := (others => '0');
61 bus_handle : in bus_master_t := register_bus_master;
62 message : in string := ""
63 );
64
65 -- Check that the current value of the 'increment' field in the 'config' register
66 -- equals the given 'expected' value.
67 procedure check_counter_config_increment_equal(
68 signal net : inout network_t;
69 expected : in counter_config_increment_t;
70 base_address : in addr_t := (others => '0');
71 bus_handle : in bus_master_t := register_bus_master;
72 message : in string := ""
73 );
74 -- ---------------------------------------------------------------------------
75
76 -- ---------------------------------------------------------------------------
77 -- Check that the current value of the 'status' register
78 -- equals the given 'expected' value as a plain SLV casted to integer.
79 procedure check_counter_status_equal(
80 signal net : inout network_t;
81 expected : in integer;
82 base_address : in addr_t := (others => '0');
83 bus_handle : in bus_master_t := register_bus_master;
84 message : in string := ""
85 );
86
87 -- Check that the current value of the 'status' register
88 -- equals the given 'expected' value.
89 procedure check_counter_status_equal(
90 signal net : inout network_t;
91 expected : in counter_status_t;
92 base_address : in addr_t := (others => '0');
93 bus_handle : in bus_master_t := register_bus_master;
94 message : in string := ""
95 );
96
97 -- Check that the current value of the 'enabled' field in the 'status' register
98 -- equals the given 'expected' value.
99 procedure check_counter_status_enabled_equal(
100 signal net : inout network_t;
101 expected : in std_ulogic;
102 base_address : in addr_t := (others => '0');
103 bus_handle : in bus_master_t := register_bus_master;
104 message : in string := ""
105 );
106
107 -- Check that the current value of the 'pulse_count' field in the 'status' register
108 -- equals the given 'expected' value.
109 procedure check_counter_status_pulse_count_equal(
110 signal net : inout network_t;
111 expected : in counter_status_pulse_count_t;
112 base_address : in addr_t := (others => '0');
113 bus_handle : in bus_master_t := register_bus_master;
114 message : in string := ""
115 );
116 -- ---------------------------------------------------------------------------
117
118end package;
119
120package body counter_register_check_pkg is
121
122 -- ---------------------------------------------------------------------------
123 -- Check that the current value of the 'config' register
124 -- equals the given 'expected' value as a plain SLV casted to integer.
125 procedure check_counter_config_equal(
126 signal net : inout network_t;
127 expected : in integer;
128 base_address : in addr_t := (others => '0');
129 bus_handle : in bus_master_t := register_bus_master;
130 message : in string := ""
131 ) is
132 constant register_array_message : string := "";
133 function base_address_message return string is
134 begin
135 if base_address /= 0 then
136 return " (at base address " & hex_image(std_logic_vector(base_address)) & ")";
137 end if;
138
139 return "";
140 end function;
141 constant base_message : string := (
142 "Checking the 'config' register"
143 & register_array_message
144 & base_address_message
145 & "."
146 );
147 function get_message return string is
148 begin
149 if message = "" then
150 return base_message;
151 end if;
152
153 return base_message & " " & message & ".";
154 end function;
155
156 variable got : integer;
157 begin
158 read_counter_config(
159 net => net,
160 value => got,
161 base_address => base_address,
162 bus_handle => bus_handle
163 );
164
165 check_equal(got=>got, expected=>expected, msg=>get_message);
166 end procedure;
167
168 -- Check that the current value of the 'config' register
169 -- equals the given 'expected' value.
170 procedure check_counter_config_equal(
171 signal net : inout network_t;
172 expected : in counter_config_t;
173 base_address : in addr_t := (others => '0');
174 bus_handle : in bus_master_t := register_bus_master;
175 message : in string := ""
176 ) is
177 constant register_array_message : string := "";
178 function base_address_message return string is
179 begin
180 if base_address /= 0 then
181 return " (at base address " & hex_image(std_logic_vector(base_address)) & ")";
182 end if;
183
184 return "";
185 end function;
186 constant base_message : string := (
187 "Checking the 'config' register"
188 & register_array_message
189 & base_address_message
190 & "."
191 );
192 function get_message return string is
193 begin
194 if message = "" then
195 return base_message;
196 end if;
197
198 return base_message & " " & message & ".";
199 end function;
200
201 variable got : counter_config_t;
202 begin
203 read_counter_config(
204 net => net,
205 value => got,
206 base_address => base_address,
207 bus_handle => bus_handle
208 );
209
210 if got /= expected then
211 failing_check(
212 checker => default_checker,
213 msg => p_std_msg(
214 check_result => "Equality check failed",
215 msg => get_message,
216 ctx => (
217 "Got " & to_string(to_slv(got)) & ". Expected " & to_string(to_slv(expected)) & "."
218 )
219 )
220 );
221 end if;
222 end procedure;
223
224 -- Check that the current value of the 'condition' field in the 'config' register
225 -- equals the given 'expected' value.
226 procedure check_counter_config_condition_equal(
227 signal net : inout network_t;
228 expected : in counter_config_condition_t;
229 base_address : in addr_t := (others => '0');
230 bus_handle : in bus_master_t := register_bus_master;
231 message : in string := ""
232 ) is
233 constant register_array_message : string := "";
234 function base_address_message return string is
235 begin
236 if base_address /= 0 then
237 return " (at base address " & hex_image(std_logic_vector(base_address)) & ")";
238 end if;
239
240 return "";
241 end function;
242 constant base_message : string := (
243 "Checking the 'condition' field in the 'config' register"
244 & register_array_message
245 & base_address_message
246 & "."
247 );
248 function get_message return string is
249 begin
250 if message = "" then
251 return base_message;
252 end if;
253
254 return base_message & " " & message & ".";
255 end function;
256
257 variable got_reg : counter_config_t := counter_config_init;
258 variable got : counter_config_condition_t := counter_config_condition_init;
259 begin
260 read_counter_config(
261 net => net,
262 value => got_reg,
263 base_address => base_address,
264 bus_handle => bus_handle
265 );
266 got := got_reg.condition;
267
268 if got /= expected then
269 failing_check(
270 checker => default_checker,
271 msg => p_std_msg(
272 check_result => "Equality check failed",
273 msg => get_message,
274 ctx => (
275 "Got " & to_string(got) & "."
276 & " Expected " & to_string(expected) & "."
277 )
278 )
279 );
280 end if;
281 end procedure;
282
283 -- Check that the current value of the 'increment' field in the 'config' register
284 -- equals the given 'expected' value.
285 procedure check_counter_config_increment_equal(
286 signal net : inout network_t;
287 expected : in counter_config_increment_t;
288 base_address : in addr_t := (others => '0');
289 bus_handle : in bus_master_t := register_bus_master;
290 message : in string := ""
291 ) is
292 constant register_array_message : string := "";
293 function base_address_message return string is
294 begin
295 if base_address /= 0 then
296 return " (at base address " & hex_image(std_logic_vector(base_address)) & ")";
297 end if;
298
299 return "";
300 end function;
301 constant base_message : string := (
302 "Checking the 'increment' field in the 'config' register"
303 & register_array_message
304 & base_address_message
305 & "."
306 );
307 function get_message return string is
308 begin
309 if message = "" then
310 return base_message;
311 end if;
312
313 return base_message & " " & message & ".";
314 end function;
315
316 variable got_reg : counter_config_t := counter_config_init;
317 variable got : counter_config_increment_t := counter_config_increment_init;
318 begin
319 read_counter_config(
320 net => net,
321 value => got_reg,
322 base_address => base_address,
323 bus_handle => bus_handle
324 );
325 got := got_reg.increment;
326
327 check_equal(got=>got, expected=>expected, msg=>get_message);
328 end procedure;
329 -- ---------------------------------------------------------------------------
330
331 -- ---------------------------------------------------------------------------
332 -- Check that the current value of the 'status' register
333 -- equals the given 'expected' value as a plain SLV casted to integer.
334 procedure check_counter_status_equal(
335 signal net : inout network_t;
336 expected : in integer;
337 base_address : in addr_t := (others => '0');
338 bus_handle : in bus_master_t := register_bus_master;
339 message : in string := ""
340 ) is
341 constant register_array_message : string := "";
342 function base_address_message return string is
343 begin
344 if base_address /= 0 then
345 return " (at base address " & hex_image(std_logic_vector(base_address)) & ")";
346 end if;
347
348 return "";
349 end function;
350 constant base_message : string := (
351 "Checking the 'status' register"
352 & register_array_message
353 & base_address_message
354 & "."
355 );
356 function get_message return string is
357 begin
358 if message = "" then
359 return base_message;
360 end if;
361
362 return base_message & " " & message & ".";
363 end function;
364
365 variable got : integer;
366 begin
367 read_counter_status(
368 net => net,
369 value => got,
370 base_address => base_address,
371 bus_handle => bus_handle
372 );
373
374 check_equal(got=>got, expected=>expected, msg=>get_message);
375 end procedure;
376
377 -- Check that the current value of the 'status' register
378 -- equals the given 'expected' value.
379 procedure check_counter_status_equal(
380 signal net : inout network_t;
381 expected : in counter_status_t;
382 base_address : in addr_t := (others => '0');
383 bus_handle : in bus_master_t := register_bus_master;
384 message : in string := ""
385 ) is
386 constant register_array_message : string := "";
387 function base_address_message return string is
388 begin
389 if base_address /= 0 then
390 return " (at base address " & hex_image(std_logic_vector(base_address)) & ")";
391 end if;
392
393 return "";
394 end function;
395 constant base_message : string := (
396 "Checking the 'status' register"
397 & register_array_message
398 & base_address_message
399 & "."
400 );
401 function get_message return string is
402 begin
403 if message = "" then
404 return base_message;
405 end if;
406
407 return base_message & " " & message & ".";
408 end function;
409
410 variable got : counter_status_t;
411 begin
412 read_counter_status(
413 net => net,
414 value => got,
415 base_address => base_address,
416 bus_handle => bus_handle
417 );
418
419 if got /= expected then
420 failing_check(
421 checker => default_checker,
422 msg => p_std_msg(
423 check_result => "Equality check failed",
424 msg => get_message,
425 ctx => (
426 "Got " & to_string(to_slv(got)) & ". Expected " & to_string(to_slv(expected)) & "."
427 )
428 )
429 );
430 end if;
431 end procedure;
432
433 -- Check that the current value of the 'enabled' field in the 'status' register
434 -- equals the given 'expected' value.
435 procedure check_counter_status_enabled_equal(
436 signal net : inout network_t;
437 expected : in std_ulogic;
438 base_address : in addr_t := (others => '0');
439 bus_handle : in bus_master_t := register_bus_master;
440 message : in string := ""
441 ) is
442 constant register_array_message : string := "";
443 function base_address_message return string is
444 begin
445 if base_address /= 0 then
446 return " (at base address " & hex_image(std_logic_vector(base_address)) & ")";
447 end if;
448
449 return "";
450 end function;
451 constant base_message : string := (
452 "Checking the 'enabled' field in the 'status' register"
453 & register_array_message
454 & base_address_message
455 & "."
456 );
457 function get_message return string is
458 begin
459 if message = "" then
460 return base_message;
461 end if;
462
463 return base_message & " " & message & ".";
464 end function;
465
466 variable got_reg : counter_status_t := counter_status_init;
467 variable got : std_ulogic := counter_status_enabled_init;
468 begin
469 read_counter_status(
470 net => net,
471 value => got_reg,
472 base_address => base_address,
473 bus_handle => bus_handle
474 );
475 got := got_reg.enabled;
476
477 check_equal(got=>got, expected=>expected, msg=>get_message);
478 end procedure;
479
480 -- Check that the current value of the 'pulse_count' field in the 'status' register
481 -- equals the given 'expected' value.
482 procedure check_counter_status_pulse_count_equal(
483 signal net : inout network_t;
484 expected : in counter_status_pulse_count_t;
485 base_address : in addr_t := (others => '0');
486 bus_handle : in bus_master_t := register_bus_master;
487 message : in string := ""
488 ) is
489 constant register_array_message : string := "";
490 function base_address_message return string is
491 begin
492 if base_address /= 0 then
493 return " (at base address " & hex_image(std_logic_vector(base_address)) & ")";
494 end if;
495
496 return "";
497 end function;
498 constant base_message : string := (
499 "Checking the 'pulse_count' field in the 'status' register"
500 & register_array_message
501 & base_address_message
502 & "."
503 );
504 function get_message return string is
505 begin
506 if message = "" then
507 return base_message;
508 end if;
509
510 return base_message & " " & message & ".";
511 end function;
512
513 variable got_reg : counter_status_t := counter_status_init;
514 variable got : counter_status_pulse_count_t := counter_status_pulse_count_init;
515 begin
516 read_counter_status(
517 net => net,
518 value => got_reg,
519 base_address => base_address,
520 bus_handle => bus_handle
521 );
522 got := got_reg.pulse_count;
523
524 check_equal(got=>got, expected=>expected, msg=>get_message);
525 end procedure;
526 -- ---------------------------------------------------------------------------
527
528end package body;
Generated VHDL simulation wait until package
Below is the generated register simulation wait until package, created from the TOML file above via
the VhdlSimulationWaitUntilPackageGenerator
class.
It is used by the VHDL example testbench to wait for registers to assume a give value.
Click to expand/collapse code.
1-- -----------------------------------------------------------------------------
2-- This file is automatically generated by hdl-registers version 7.0.2-dev.
3-- Code generator VhdlSimulationWaitUntilPackageGenerator version 1.0.0.
4-- Generated 2025-01-21 20:52 from file regs_counter.toml at commit 3c3e6c67d817.
5-- Register hash 49f02a8daa9dd4bc3dadeb2a1cfd61dcc38c3864.
6-- -----------------------------------------------------------------------------
7
8library ieee;
9use ieee.fixed_pkg.all;
10use ieee.std_logic_1164.all;
11use ieee.numeric_std.all;
12
13library vunit_lib;
14use vunit_lib.bus_master_pkg.bus_master_t;
15use vunit_lib.bus_master_pkg.wait_until_read_equals;
16use vunit_lib.com_types_pkg.max_timeout;
17use vunit_lib.com_types_pkg.network_t;
18use vunit_lib.string_ops.hex_image;
19
20library common;
21use common.addr_pkg.addr_t;
22use common.addr_pkg.addr_width;
23
24library register_file;
25use register_file.register_file_pkg.register_t;
26use register_file.register_operations_pkg.register_bus_master;
27
28use work.counter_regs_pkg.all;
29use work.counter_register_record_pkg.all;
30
31
32package counter_register_wait_until_pkg is
33
34 -- ---------------------------------------------------------------------------
35 -- Wait until the 'config' register equals the given 'value'.
36 procedure wait_until_counter_config_equals(
37 signal net : inout network_t;
38 value : in counter_config_t;
39 base_address : in addr_t := (others => '0');
40 bus_handle : in bus_master_t := register_bus_master;
41 timeout : delay_length := max_timeout;
42 message : string := ""
43 );
44
45 -- Wait until the 'condition' field in the 'config' register equals the given 'value'.
46 procedure wait_until_counter_config_condition_equals(
47 signal net : inout network_t;
48 value : in counter_config_condition_t;
49 base_address : in addr_t := (others => '0');
50 bus_handle : in bus_master_t := register_bus_master;
51 timeout : delay_length := max_timeout;
52 message : string := ""
53 );
54
55 -- Wait until the 'increment' field in the 'config' register equals the given 'value'.
56 procedure wait_until_counter_config_increment_equals(
57 signal net : inout network_t;
58 value : in counter_config_increment_t;
59 base_address : in addr_t := (others => '0');
60 bus_handle : in bus_master_t := register_bus_master;
61 timeout : delay_length := max_timeout;
62 message : string := ""
63 );
64 -- ---------------------------------------------------------------------------
65
66 -- ---------------------------------------------------------------------------
67 -- Wait until the 'status' register equals the given 'value'.
68 procedure wait_until_counter_status_equals(
69 signal net : inout network_t;
70 value : in counter_status_t;
71 base_address : in addr_t := (others => '0');
72 bus_handle : in bus_master_t := register_bus_master;
73 timeout : delay_length := max_timeout;
74 message : string := ""
75 );
76
77 -- Wait until the 'enabled' field in the 'status' register equals the given 'value'.
78 procedure wait_until_counter_status_enabled_equals(
79 signal net : inout network_t;
80 value : in std_ulogic;
81 base_address : in addr_t := (others => '0');
82 bus_handle : in bus_master_t := register_bus_master;
83 timeout : delay_length := max_timeout;
84 message : string := ""
85 );
86
87 -- Wait until the 'pulse_count' field in the 'status' register equals the given 'value'.
88 procedure wait_until_counter_status_pulse_count_equals(
89 signal net : inout network_t;
90 value : in counter_status_pulse_count_t;
91 base_address : in addr_t := (others => '0');
92 bus_handle : in bus_master_t := register_bus_master;
93 timeout : delay_length := max_timeout;
94 message : string := ""
95 );
96 -- ---------------------------------------------------------------------------
97
98end package;
99
100package body counter_register_wait_until_pkg is
101
102 -- ---------------------------------------------------------------------------
103 -- Wait until the 'config' register equals the given 'value'.
104 procedure wait_until_counter_config_equals(
105 signal net : inout network_t;
106 value : in counter_config_t;
107 base_address : in addr_t := (others => '0');
108 bus_handle : in bus_master_t := register_bus_master;
109 timeout : delay_length := max_timeout;
110 message : string := ""
111 ) is
112 constant reg_value : register_t := to_slv(value);
113
114 constant reg_index : counter_register_range := counter_config;
115 constant reg_address : addr_t := base_address + to_unsigned(4 * reg_index, addr_width);
116
117 constant register_array_message : string := "";
118 function base_address_message return string is
119 begin
120 if base_address /= 0 then
121 return " (at base address " & hex_image(std_logic_vector(base_address)) & ")";
122 end if;
123
124 return "";
125 end function;
126 constant base_message : string := (
127 "Timeout while waiting for the 'config' register"
128 & register_array_message
129 & base_address_message
130 & " to equal the given value: "
131 & to_string(reg_value)
132 & "."
133 );
134 function get_message return string is
135 begin
136 if message = "" then
137 return base_message;
138 end if;
139
140 return base_message & " " & message & ".";
141 end function;
142 begin
143 wait_until_read_equals(
144 net => net,
145 bus_handle => bus_handle,
146 addr => std_ulogic_vector(reg_address),
147 value => reg_value,
148 timeout => timeout,
149 msg => get_message
150 );
151 end procedure;
152
153 -- Wait until the 'condition' field in the 'config' register equals the given 'value'.
154 procedure wait_until_counter_config_condition_equals(
155 signal net : inout network_t;
156 value : in counter_config_condition_t;
157 base_address : in addr_t := (others => '0');
158 bus_handle : in bus_master_t := register_bus_master;
159 timeout : delay_length := max_timeout;
160 message : string := ""
161 ) is
162 constant reg_value : register_t := (
163 counter_config_condition => to_slv(value),
164 others => '-'
165 );
166
167 constant reg_index : counter_register_range := counter_config;
168 constant reg_address : addr_t := base_address + to_unsigned(4 * reg_index, addr_width);
169
170 constant register_array_message : string := "";
171 function base_address_message return string is
172 begin
173 if base_address /= 0 then
174 return " (at base address " & hex_image(std_logic_vector(base_address)) & ")";
175 end if;
176
177 return "";
178 end function;
179 constant base_message : string := (
180 "Timeout while waiting for the 'condition' field in the 'config' register"
181 & register_array_message
182 & base_address_message
183 & " to equal the given value: "
184 & to_string(reg_value)
185 & "."
186 );
187 function get_message return string is
188 begin
189 if message = "" then
190 return base_message;
191 end if;
192
193 return base_message & " " & message & ".";
194 end function;
195 begin
196 wait_until_read_equals(
197 net => net,
198 bus_handle => bus_handle,
199 addr => std_ulogic_vector(reg_address),
200 value => reg_value,
201 timeout => timeout,
202 msg => get_message
203 );
204 end procedure;
205
206 -- Wait until the 'increment' field in the 'config' register equals the given 'value'.
207 procedure wait_until_counter_config_increment_equals(
208 signal net : inout network_t;
209 value : in counter_config_increment_t;
210 base_address : in addr_t := (others => '0');
211 bus_handle : in bus_master_t := register_bus_master;
212 timeout : delay_length := max_timeout;
213 message : string := ""
214 ) is
215 constant reg_value : register_t := (
216 counter_config_increment => to_counter_config_increment_slv(value),
217 others => '-'
218 );
219
220 constant reg_index : counter_register_range := counter_config;
221 constant reg_address : addr_t := base_address + to_unsigned(4 * reg_index, addr_width);
222
223 constant register_array_message : string := "";
224 function base_address_message return string is
225 begin
226 if base_address /= 0 then
227 return " (at base address " & hex_image(std_logic_vector(base_address)) & ")";
228 end if;
229
230 return "";
231 end function;
232 constant base_message : string := (
233 "Timeout while waiting for the 'increment' field in the 'config' register"
234 & register_array_message
235 & base_address_message
236 & " to equal the given value: "
237 & to_string(reg_value)
238 & "."
239 );
240 function get_message return string is
241 begin
242 if message = "" then
243 return base_message;
244 end if;
245
246 return base_message & " " & message & ".";
247 end function;
248 begin
249 wait_until_read_equals(
250 net => net,
251 bus_handle => bus_handle,
252 addr => std_ulogic_vector(reg_address),
253 value => reg_value,
254 timeout => timeout,
255 msg => get_message
256 );
257 end procedure;
258 -- ---------------------------------------------------------------------------
259
260 -- ---------------------------------------------------------------------------
261 -- Wait until the 'status' register equals the given 'value'.
262 procedure wait_until_counter_status_equals(
263 signal net : inout network_t;
264 value : in counter_status_t;
265 base_address : in addr_t := (others => '0');
266 bus_handle : in bus_master_t := register_bus_master;
267 timeout : delay_length := max_timeout;
268 message : string := ""
269 ) is
270 constant reg_value : register_t := to_slv(value);
271
272 constant reg_index : counter_register_range := counter_status;
273 constant reg_address : addr_t := base_address + to_unsigned(4 * reg_index, addr_width);
274
275 constant register_array_message : string := "";
276 function base_address_message return string is
277 begin
278 if base_address /= 0 then
279 return " (at base address " & hex_image(std_logic_vector(base_address)) & ")";
280 end if;
281
282 return "";
283 end function;
284 constant base_message : string := (
285 "Timeout while waiting for the 'status' register"
286 & register_array_message
287 & base_address_message
288 & " to equal the given value: "
289 & to_string(reg_value)
290 & "."
291 );
292 function get_message return string is
293 begin
294 if message = "" then
295 return base_message;
296 end if;
297
298 return base_message & " " & message & ".";
299 end function;
300 begin
301 wait_until_read_equals(
302 net => net,
303 bus_handle => bus_handle,
304 addr => std_ulogic_vector(reg_address),
305 value => reg_value,
306 timeout => timeout,
307 msg => get_message
308 );
309 end procedure;
310
311 -- Wait until the 'enabled' field in the 'status' register equals the given 'value'.
312 procedure wait_until_counter_status_enabled_equals(
313 signal net : inout network_t;
314 value : in std_ulogic;
315 base_address : in addr_t := (others => '0');
316 bus_handle : in bus_master_t := register_bus_master;
317 timeout : delay_length := max_timeout;
318 message : string := ""
319 ) is
320 constant reg_value : register_t := (
321 counter_status_enabled => value,
322 others => '-'
323 );
324
325 constant reg_index : counter_register_range := counter_status;
326 constant reg_address : addr_t := base_address + to_unsigned(4 * reg_index, addr_width);
327
328 constant register_array_message : string := "";
329 function base_address_message return string is
330 begin
331 if base_address /= 0 then
332 return " (at base address " & hex_image(std_logic_vector(base_address)) & ")";
333 end if;
334
335 return "";
336 end function;
337 constant base_message : string := (
338 "Timeout while waiting for the 'enabled' field in the 'status' register"
339 & register_array_message
340 & base_address_message
341 & " to equal the given value: "
342 & to_string(reg_value)
343 & "."
344 );
345 function get_message return string is
346 begin
347 if message = "" then
348 return base_message;
349 end if;
350
351 return base_message & " " & message & ".";
352 end function;
353 begin
354 wait_until_read_equals(
355 net => net,
356 bus_handle => bus_handle,
357 addr => std_ulogic_vector(reg_address),
358 value => reg_value,
359 timeout => timeout,
360 msg => get_message
361 );
362 end procedure;
363
364 -- Wait until the 'pulse_count' field in the 'status' register equals the given 'value'.
365 procedure wait_until_counter_status_pulse_count_equals(
366 signal net : inout network_t;
367 value : in counter_status_pulse_count_t;
368 base_address : in addr_t := (others => '0');
369 bus_handle : in bus_master_t := register_bus_master;
370 timeout : delay_length := max_timeout;
371 message : string := ""
372 ) is
373 constant reg_value : register_t := (
374 counter_status_pulse_count => to_counter_status_pulse_count_slv(value),
375 others => '-'
376 );
377
378 constant reg_index : counter_register_range := counter_status;
379 constant reg_address : addr_t := base_address + to_unsigned(4 * reg_index, addr_width);
380
381 constant register_array_message : string := "";
382 function base_address_message return string is
383 begin
384 if base_address /= 0 then
385 return " (at base address " & hex_image(std_logic_vector(base_address)) & ")";
386 end if;
387
388 return "";
389 end function;
390 constant base_message : string := (
391 "Timeout while waiting for the 'pulse_count' field in the 'status' register"
392 & register_array_message
393 & base_address_message
394 & " to equal the given value: "
395 & to_string(reg_value)
396 & "."
397 );
398 function get_message return string is
399 begin
400 if message = "" then
401 return base_message;
402 end if;
403
404 return base_message & " " & message & ".";
405 end function;
406 begin
407 wait_until_read_equals(
408 net => net,
409 bus_handle => bus_handle,
410 addr => std_ulogic_vector(reg_address),
411 value => reg_value,
412 timeout => timeout,
413 msg => get_message
414 );
415 end procedure;
416 -- ---------------------------------------------------------------------------
417
418end package body;
Performance
Since generation of VHDL packages is usually run in real time (e.g. before running a simulation) the
speed of the tool is important.
In order the save time, RegisterCodeGenerator.create_if_needed()
maintains a hash of the
register definitions, and will only generate the VHDL file when necessary.
Hence it is recommended to call this function as opposed to RegisterCodeGenerator.create()
which will waste time by always re-creating, even when it is not necessary.
See here for a comparison with the performance of other tools.
Dependencies
Most of the generated code depends on VHDL packages from hdl-modules version 4.0.0 or greater.
The VhdlRegisterPackageGenerator
and VhdlRecordPackageGenerator
packages
depend on register_file_pkg.vhd.
Can be downloaded from GitHub here:
https://github.com/hdl-modules/hdl-modules/blob/main/modules/register_file/src/register_file_pkg.vhd
The VhdlSimulationReadWritePackageGenerator
and
VhdlSimulationWaitUntilPackageGenerator
packages
furthermore depend on register_operations_pkg.vhd and addr_pkg.vhd.
The VhdlAxiLiteWrapperGenerator
package also depends on axi_lite_pkg.vhd.
Unresolved types
The generated VHDL uses unresolved types
(e.g. std_ulogic_vector
instead of std_logic_vector
) consistently.
This means that accidental multiple drivers of a signal will result in an error when simulating
or synthesizing the design.
Since e.g. std_logic
is a sub-type of std_ulogic
in VHDL-2008, it is no problem if
hdl-registers components are integrated in a code base that still uses the resolved types.
I.e. a std_logic
signal can be assigned to a hdl-registers signal of type std_ulogic
,
and vice versa, without problem.
Further tools for simplifying register handling
There is a large eco-system of register-related components in the hdl-modules project. Firstly there are wrappers in the bfm library for easier working with VUnit verification components. Furthermore there is a large number of synthesizable AXI/AXI-Lite components available that enable the register bus:
AXI-to-AXI-Lite converter: axi_to_axi_lite.vhd,
AXI/AXI-Lite crossbar: axi_simple_read_crossbar.vhd, axi_simple_write_crossbar.vhd, axi_lite_simple_read_crossbar.vhd, axi_lite_simple_write_crossbar.vhd,
AXI-Lite mux (splitter): axi_lite_mux.vhd,
AXI-Lite clock domain crossing: axi_lite_cdc.vhd,
etc…
See the register_file library, axi library and axi_lite library for more details.