VHDL generator
A large ecosystem of VHDL artifacts can be generated that support both implementation and simulation in your project. For synthesis:
VhdlRegisterPackageGenerator
generates the base VHDL package with indexes, modes, types, and conversion functions.VhdlRecordPackageGenerator
generates a package with register records that use native VHDL types for all fields, along with conversion functions.VhdlAxiLiteWrapperGenerator
generates a VHDL entity that wraps an AXI-Lite general register file, and exposes register values to application using the natively typed records.
For simulation:
VhdlSimulationReadWritePackageGenerator
generates a package with procedures for reading and writing register/field values as a one-liner.VhdlSimulationCheckPackageGenerator
generates a package with procedures for checking current register/field values against a given expected value.VhdlSimulationWaitUntilPackageGenerator
generates a package with procedures for waiting until a readable register/field assumes a given value.
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[conf]
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 ``conf`` 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.
1import sys
2from pathlib import Path
3
4from hdl_registers.generator.vhdl.axi_lite.wrapper import VhdlAxiLiteWrapperGenerator
5from hdl_registers.generator.vhdl.record_package import VhdlRecordPackageGenerator
6from hdl_registers.generator.vhdl.register_package import VhdlRegisterPackageGenerator
7from hdl_registers.generator.vhdl.simulation.check_package import (
8 VhdlSimulationCheckPackageGenerator,
9)
10from hdl_registers.generator.vhdl.simulation.read_write_package import (
11 VhdlSimulationReadWritePackageGenerator,
12)
13from hdl_registers.generator.vhdl.simulation.wait_until_package import (
14 VhdlSimulationWaitUntilPackageGenerator,
15)
16from hdl_registers.parser.toml import from_toml
17
18THIS_DIR = Path(__file__).parent
19
20
21def main(output_folder: Path) -> None:
22 """
23 Create register VHDL artifacts from the "counter" example module.
24 """
25 register_list = from_toml(
26 name="counter", toml_file=THIS_DIR.parent / "example_counter" / "regs_counter.toml"
27 )
28
29 VhdlRegisterPackageGenerator(
30 register_list=register_list, output_folder=output_folder
31 ).create_if_needed()
32
33 VhdlRecordPackageGenerator(
34 register_list=register_list, output_folder=output_folder
35 ).create_if_needed()
36
37 VhdlAxiLiteWrapperGenerator(
38 register_list=register_list, output_folder=output_folder
39 ).create_if_needed()
40
41 VhdlSimulationReadWritePackageGenerator(
42 register_list=register_list, output_folder=output_folder
43 ).create_if_needed()
44
45 VhdlSimulationCheckPackageGenerator(
46 register_list=register_list, output_folder=output_folder
47 ).create_if_needed()
48
49 VhdlSimulationWaitUntilPackageGenerator(
50 register_list=register_list, output_folder=output_folder
51 ).create_if_needed()
52
53
54if __name__ == "__main__":
55 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.conf 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.conf.condition is
97 when condition_clock_cycles =>
98 count <= count + regs_down.conf.increment;
99
100 when condition_clock_cycles_with_enable =>
101 if clock_enable then
102 count <= count + regs_down.conf.increment;
103 end if;
104
105 when condition_enable_edges =>
106 if clock_enable /= clock_enable_p1 then
107 count <= count + regs_down.conf.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_conf
.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 conf : counter_conf_t := counter_conf_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 conf.condition := condition_clock_cycles;
55 conf.increment := 13;
56
57 elsif run("test_count_clock_cycles_with_enable") then
58 conf.condition := condition_clock_cycles_with_enable;
59 conf.increment := 8;
60
61 clock_enable <= '1';
62 end if;
63
64 -- Set configuration, which depends on test case.
65 write_counter_conf(net=>net, value=>conf);
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 8.0.1-dev.
3-- Code generator VhdlRegisterPackageGenerator version 2.0.0.
4-- Generated 2025-05-05 20:52 from file regs_counter.toml at Git commit f53f19ab11e0.
5-- Register hash e0b7d8e366d3777f3ef21d8e44540f964701e9be.
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_conf : 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 'conf' register.
52 -- Range of the 'condition' field.
53 subtype counter_conf_condition is natural range 1 downto 0;
54 -- Width of the 'condition' field.
55 constant counter_conf_condition_width : positive := 2;
56 -- Type for the 'condition' field.
57 type counter_conf_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_conf_condition_init : counter_conf_condition_t := condition_clock_cycles;
64 -- Type for the 'condition' field as an SLV.
65 subtype counter_conf_condition_slv_t is std_ulogic_vector(1 downto 0);
66 -- Cast a 'condition' field value to SLV.
67 function to_slv(data : counter_conf_condition_t) return counter_conf_condition_slv_t;
68 -- Get a 'condition' field value from a register value.
69 function to_counter_conf_condition(data : register_t) return counter_conf_condition_t;
70
71 -- Range of the 'increment' field.
72 subtype counter_conf_increment is natural range 5 downto 2;
73 -- Width of the 'increment' field.
74 constant counter_conf_increment_width : positive := 4;
75 -- Type for the 'increment' field.
76 subtype counter_conf_increment_t is integer range 0 to 15;
77 -- Default value of the 'increment' field.
78 constant counter_conf_increment_init : counter_conf_increment_t := 0;
79 -- Type for the 'increment' field as an SLV.
80 subtype counter_conf_increment_slv_t is std_ulogic_vector(3 downto 0);
81 -- Cast a 'increment' field value to SLV.
82 function to_counter_conf_increment_slv(data : counter_conf_increment_t) return counter_conf_increment_slv_t;
83 -- Get a 'increment' field value from a register value.
84 function to_counter_conf_increment(data : register_t) return counter_conf_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_conf, 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_conf_condition_t) return counter_conf_condition_slv_t is
138 constant data_int : natural := counter_conf_condition_t'pos(data);
139 constant result : counter_conf_condition_slv_t := std_ulogic_vector(
140 to_unsigned(data_int, counter_conf_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_conf_condition(data : register_t) return counter_conf_condition_t is
148 constant field_slv : counter_conf_condition_slv_t := data(counter_conf_condition);
149 constant field_int : natural := to_integer(unsigned(field_slv));
150 constant result : counter_conf_condition_t := counter_conf_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_conf_increment_slv(data : counter_conf_increment_t) return counter_conf_increment_slv_t is
157 constant result : counter_conf_increment_slv_t := std_ulogic_vector(to_unsigned(data, counter_conf_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_conf_increment(data : register_t) return counter_conf_increment_t is
164 constant result : integer := to_integer(unsigned(data(counter_conf_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 8.0.1-dev.
3-- Code generator VhdlRecordPackageGenerator version 1.0.0.
4-- Generated 2025-05-05 20:52 from file regs_counter.toml at Git commit f53f19ab11e0.
5-- Register hash e0b7d8e366d3777f3ef21d8e44540f964701e9be.
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 'conf' register as a record.
24 type counter_conf_t is record
25 condition : counter_conf_condition_t;
26 increment : counter_conf_increment_t;
27 end record;
28 -- Default value for the 'conf' register as a record.
29 constant counter_conf_init : counter_conf_t := (
30 condition => counter_conf_condition_init,
31 increment => counter_conf_increment_init
32 );
33 -- Convert a record of the 'conf' register to SLV.
34 function to_slv(data : counter_conf_t) return register_t;
35 -- Convert an SLV register value to the record for the 'conf' register.
36 function to_counter_conf(data : register_t) return counter_conf_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 conf : counter_conf_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 conf => counter_conf_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 conf : 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 conf : 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_conf_t) return register_t is
137 variable result : register_t := (others => '-');
138 begin
139 result(counter_conf_condition) := to_slv(data.condition);
140 result(counter_conf_increment) := to_counter_conf_increment_slv(data.increment);
141
142 return result;
143 end function;
144
145 function to_counter_conf(data : register_t) return counter_conf_t is
146 variable result : counter_conf_t := counter_conf_init;
147 begin
148 result.condition := to_counter_conf_condition(data);
149 result.increment := to_counter_conf_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.conf := to_counter_conf(data(counter_conf));
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.conf := data(counter_conf);
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.conf := data(counter_conf);
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 8.0.1-dev.
3-- Code generator VhdlAxiLiteWrapperGenerator version 1.0.3.
4-- Generated 2025-05-05 20:52 from file regs_counter.toml at Git commit f53f19ab11e0.
5-- Register hash e0b7d8e366d3777f3ef21d8e44540f964701e9be.
6-- -----------------------------------------------------------------------------
7
8-- -----------------------------------------------------------------------------
9-- AXI-Lite register file for the 'counter' module registers.
10-- Sets correct generics, and performs conversion to the easy-to-use register record types.
11-- -----------------------------------------------------------------------------
12
13library ieee;
14use ieee.std_logic_1164.all;
15
16-- This VHDL file is a required dependency:
17-- https://github.com/hdl-modules/hdl-modules/blob/main/modules/axi_lite/src/axi_lite_pkg.vhd
18-- See https://hdl-registers.com/rst/generator/generator_vhdl.html for dependency details.
19library axi_lite;
20use axi_lite.axi_lite_pkg.all;
21
22-- This VHDL file is a required dependency:
23-- https://github.com/hdl-modules/hdl-modules/blob/main/modules/register_file/src/axi_lite_register_file.vhd
24-- See https://hdl-registers.com/rst/generator/generator_vhdl.html for dependency details.
25library register_file;
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 -- Active-high synchronous reset.
35 -- The code in this entity uses initial values so an initial reset is NOT necessary.
36 -- This port can safely be left unconnected and tied to zero.
37 -- If asserted, it will reset the AXI-Lite handshaking state as well as all register values.
38 reset : in std_ulogic := '0';
39 --# {}
40 --# Register control bus.
41 axi_lite_m2s : in axi_lite_m2s_t;
42 axi_lite_s2m : out axi_lite_s2m_t := axi_lite_s2m_init;
43 --# {}
44 -- Register values.
45 regs_up : in counter_regs_up_t := counter_regs_up_init;
46 regs_down : out counter_regs_down_t := counter_regs_down_init;
47 --# {}
48 -- Each bit is pulsed for one cycle when the corresponding register is read/written.
49 reg_was_read : out counter_reg_was_read_t := counter_reg_was_read_init;
50 reg_was_written : out counter_reg_was_written_t := counter_reg_was_written_init
51 );
52end entity;
53
54architecture a of counter_register_file_axi_lite is
55
56 signal regs_up_slv, regs_down_slv : counter_regs_t := counter_regs_init;
57
58 signal reg_was_read_slv, reg_was_written_slv : counter_reg_was_accessed_t := (
59 others => '0'
60 );
61
62begin
63
64 ------------------------------------------------------------------------------
65 -- Instantiate the generic register file implementation:
66 -- https://github.com/hdl-modules/hdl-modules/blob/main/modules/register_file/src/axi_lite_register_file.vhd
67 -- See https://hdl-registers.com/rst/generator/generator_vhdl.html for dependency details.
68 axi_lite_register_file_inst : entity register_file.axi_lite_register_file
69 generic map (
70 registers => counter_register_map,
71 default_values => counter_regs_init
72 )
73 port map(
74 clk => clk,
75 reset => reset,
76 --
77 axi_lite_m2s => axi_lite_m2s,
78 axi_lite_s2m => axi_lite_s2m,
79 --
80 regs_up => regs_up_slv,
81 regs_down => regs_down_slv,
82 --
83 reg_was_read => reg_was_read_slv,
84 reg_was_written => reg_was_written_slv
85 );
86
87
88 ------------------------------------------------------------------------------
89 -- Combinatorially convert the register record to a list of SLV values that can be handled
90 -- by the generic register file implementation.
91 assign_regs_up : process(regs_up)
92 begin
93 regs_up_slv <= to_slv(regs_up);
94 end process;
95
96
97 ------------------------------------------------------------------------------
98 -- Combinatorially convert the list of SLV values from the generic register file into the record
99 -- we want to use in our application.
100 assign_regs_down : process(regs_down_slv)
101 begin
102 regs_down <= to_counter_regs_down(regs_down_slv);
103 end process;
104
105
106 ------------------------------------------------------------------------------
107 -- Combinatorially convert status mask to a record where only the applicable registers are present.
108 assign_reg_was_read : process(reg_was_read_slv)
109 begin
110 reg_was_read <= to_counter_reg_was_read(reg_was_read_slv);
111 end process;
112
113
114 ------------------------------------------------------------------------------
115 -- Combinatorially convert status mask to a record where only the applicable registers are present.
116 assign_reg_was_written : process(reg_was_written_slv)
117 begin
118 reg_was_written <= to_counter_reg_was_written(reg_was_written_slv);
119 end process;
120
121end 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 8.0.1-dev.
3-- Code generator VhdlSimulationReadWritePackageGenerator version 1.1.1.
4-- Generated 2025-05-05 20:52 from file regs_counter.toml at Git commit f53f19ab11e0.
5-- Register hash e0b7d8e366d3777f3ef21d8e44540f964701e9be.
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 register_file;
19use register_file.register_file_pkg.register_t;
20use register_file.register_file_pkg.register_width;
21use register_file.register_operations_pkg.register_bus_master;
22
23use work.counter_regs_pkg.all;
24use work.counter_register_record_pkg.all;
25
26
27package counter_register_read_write_pkg is
28
29 -- ---------------------------------------------------------------------------
30 -- Read the 'conf' register as a plain 'register_t'.
31 procedure read_counter_conf(
32 signal net : inout network_t;
33 value : out register_t;
34 base_address : in unsigned(32 - 1 downto 0) := (others => '0');
35 bus_handle : in bus_master_t := register_bus_master
36 );
37
38 -- Read the 'conf' register as an 'integer'.
39 procedure read_counter_conf(
40 signal net : inout network_t;
41 value : out integer;
42 base_address : in unsigned(32 - 1 downto 0) := (others => '0');
43 bus_handle : in bus_master_t := register_bus_master
44 );
45
46 -- Read the 'conf' register.
47 procedure read_counter_conf(
48 signal net : inout network_t;
49 value : out counter_conf_t;
50 base_address : in unsigned(32 - 1 downto 0) := (others => '0');
51 bus_handle : in bus_master_t := register_bus_master
52 );
53
54 -- Read the 'condition' field in the 'conf' register.
55 procedure read_counter_conf_condition(
56 signal net : inout network_t;
57 value : out counter_conf_condition_t;
58 base_address : in unsigned(32 - 1 downto 0) := (others => '0');
59 bus_handle : in bus_master_t := register_bus_master
60 );
61
62 -- Read the 'increment' field in the 'conf' register.
63 procedure read_counter_conf_increment(
64 signal net : inout network_t;
65 value : out counter_conf_increment_t;
66 base_address : in unsigned(32 - 1 downto 0) := (others => '0');
67 bus_handle : in bus_master_t := register_bus_master
68 );
69
70 -- Write the 'conf' register as an 'integer'.
71 procedure write_counter_conf(
72 signal net : inout network_t;
73 value : in integer;
74 base_address : in unsigned(32 - 1 downto 0) := (others => '0');
75 bus_handle : in bus_master_t := register_bus_master
76 );
77
78 -- Write the 'conf' register.
79 procedure write_counter_conf(
80 signal net : inout network_t;
81 value : in counter_conf_t;
82 base_address : in unsigned(32 - 1 downto 0) := (others => '0');
83 bus_handle : in bus_master_t := register_bus_master
84 );
85
86 -- Write the 'condition' field in the 'conf' register.
87 -- Will read-modify-write the register to set the field to the supplied 'value'.
88 procedure write_counter_conf_condition(
89 signal net : inout network_t;
90 value : in counter_conf_condition_t;
91 base_address : in unsigned(32 - 1 downto 0) := (others => '0');
92 bus_handle : in bus_master_t := register_bus_master
93 );
94
95 -- Write the 'increment' field in the 'conf' register.
96 -- Will read-modify-write the register to set the field to the supplied 'value'.
97 procedure write_counter_conf_increment(
98 signal net : inout network_t;
99 value : in counter_conf_increment_t;
100 base_address : in unsigned(32 - 1 downto 0) := (others => '0');
101 bus_handle : in bus_master_t := register_bus_master
102 );
103 -- ---------------------------------------------------------------------------
104
105 -- ---------------------------------------------------------------------------
106 -- Write the 'command' register as an 'integer'.
107 procedure write_counter_command(
108 signal net : inout network_t;
109 value : in integer;
110 base_address : in unsigned(32 - 1 downto 0) := (others => '0');
111 bus_handle : in bus_master_t := register_bus_master
112 );
113
114 -- Write the 'command' register.
115 procedure write_counter_command(
116 signal net : inout network_t;
117 value : in counter_command_t;
118 base_address : in unsigned(32 - 1 downto 0) := (others => '0');
119 bus_handle : in bus_master_t := register_bus_master
120 );
121
122 -- Write the 'start' field in the 'command' register.
123 -- Will write the whole register, with the field set to the
124 -- supplied 'value' and everything else set to default.
125 procedure write_counter_command_start(
126 signal net : inout network_t;
127 value : in std_ulogic;
128 base_address : in unsigned(32 - 1 downto 0) := (others => '0');
129 bus_handle : in bus_master_t := register_bus_master
130 );
131
132 -- Write the 'stop' field in the 'command' register.
133 -- Will write the whole register, with the field set to the
134 -- supplied 'value' and everything else set to default.
135 procedure write_counter_command_stop(
136 signal net : inout network_t;
137 value : in std_ulogic;
138 base_address : in unsigned(32 - 1 downto 0) := (others => '0');
139 bus_handle : in bus_master_t := register_bus_master
140 );
141 -- ---------------------------------------------------------------------------
142
143 -- ---------------------------------------------------------------------------
144 -- Read the 'status' register as a plain 'register_t'.
145 procedure read_counter_status(
146 signal net : inout network_t;
147 value : out register_t;
148 base_address : in unsigned(32 - 1 downto 0) := (others => '0');
149 bus_handle : in bus_master_t := register_bus_master
150 );
151
152 -- Read the 'status' register as an 'integer'.
153 procedure read_counter_status(
154 signal net : inout network_t;
155 value : out integer;
156 base_address : in unsigned(32 - 1 downto 0) := (others => '0');
157 bus_handle : in bus_master_t := register_bus_master
158 );
159
160 -- Read the 'status' register.
161 procedure read_counter_status(
162 signal net : inout network_t;
163 value : out counter_status_t;
164 base_address : in unsigned(32 - 1 downto 0) := (others => '0');
165 bus_handle : in bus_master_t := register_bus_master
166 );
167
168 -- Read the 'enabled' field in the 'status' register.
169 procedure read_counter_status_enabled(
170 signal net : inout network_t;
171 value : out std_ulogic;
172 base_address : in unsigned(32 - 1 downto 0) := (others => '0');
173 bus_handle : in bus_master_t := register_bus_master
174 );
175
176 -- Read the 'pulse_count' field in the 'status' register.
177 procedure read_counter_status_pulse_count(
178 signal net : inout network_t;
179 value : out counter_status_pulse_count_t;
180 base_address : in unsigned(32 - 1 downto 0) := (others => '0');
181 bus_handle : in bus_master_t := register_bus_master
182 );
183 -- ---------------------------------------------------------------------------
184
185end package;
186
187package body counter_register_read_write_pkg is
188
189 -- ---------------------------------------------------------------------------
190 -- Read the 'conf' register as a plain 'register_t'.
191 procedure read_counter_conf(
192 signal net : inout network_t;
193 value : out register_t;
194 base_address : in unsigned(32 - 1 downto 0) := (others => '0');
195 bus_handle : in bus_master_t := register_bus_master
196 ) is
197 constant reg_index : counter_register_range := counter_conf;
198 constant reg_address : unsigned(32 - 1 downto 0) := base_address + to_unsigned(4 * reg_index, 32);
199 variable reg_value : register_t := (others => '0');
200 begin
201 read_bus(
202 net => net,
203 bus_handle => bus_handle,
204 address => std_logic_vector(reg_address),
205 data => reg_value
206 );
207 value := reg_value;
208 end procedure;
209
210 -- Read the 'conf' register as an 'integer'.
211 procedure read_counter_conf(
212 signal net : inout network_t;
213 value : out integer;
214 base_address : in unsigned(32 - 1 downto 0) := (others => '0');
215 bus_handle : in bus_master_t := register_bus_master
216 ) is
217 constant reg_index : counter_register_range := counter_conf;
218 constant reg_address : unsigned(32 - 1 downto 0) := base_address + to_unsigned(4 * reg_index, 32);
219 variable reg_value : register_t := (others => '0');
220 begin
221 read_bus(
222 net => net,
223 bus_handle => bus_handle,
224 address => std_logic_vector(reg_address),
225 data => reg_value
226 );
227 value := to_integer(unsigned(reg_value));
228 end procedure;
229
230 -- Read the 'conf' register.
231 procedure read_counter_conf(
232 signal net : inout network_t;
233 value : out counter_conf_t;
234 base_address : in unsigned(32 - 1 downto 0) := (others => '0');
235 bus_handle : in bus_master_t := register_bus_master
236 ) is
237 constant reg_index : counter_register_range := counter_conf;
238 constant reg_address : unsigned(32 - 1 downto 0) := base_address + to_unsigned(4 * reg_index, 32);
239 variable reg_value : register_t := (others => '0');
240 begin
241 read_bus(
242 net => net,
243 bus_handle => bus_handle,
244 address => std_logic_vector(reg_address),
245 data => reg_value
246 );
247 value := to_counter_conf(reg_value);
248 end procedure;
249
250 -- Read the 'condition' field in the 'conf' register.
251 procedure read_counter_conf_condition(
252 signal net : inout network_t;
253 value : out counter_conf_condition_t;
254 base_address : in unsigned(32 - 1 downto 0) := (others => '0');
255 bus_handle : in bus_master_t := register_bus_master
256 ) is
257 variable reg_value : counter_conf_t := counter_conf_init;
258 begin
259 read_counter_conf(
260 net => net,
261 value => reg_value,
262 base_address => base_address,
263 bus_handle => bus_handle
264 );
265 value := reg_value.condition;
266 end procedure;
267
268 -- Read the 'increment' field in the 'conf' register.
269 procedure read_counter_conf_increment(
270 signal net : inout network_t;
271 value : out counter_conf_increment_t;
272 base_address : in unsigned(32 - 1 downto 0) := (others => '0');
273 bus_handle : in bus_master_t := register_bus_master
274 ) is
275 variable reg_value : counter_conf_t := counter_conf_init;
276 begin
277 read_counter_conf(
278 net => net,
279 value => reg_value,
280 base_address => base_address,
281 bus_handle => bus_handle
282 );
283 value := reg_value.increment;
284 end procedure;
285
286 -- Write the 'conf' register as an 'integer'.
287 procedure write_counter_conf(
288 signal net : inout network_t;
289 value : in integer;
290 base_address : in unsigned(32 - 1 downto 0) := (others => '0');
291 bus_handle : in bus_master_t := register_bus_master
292 ) is
293 constant reg_index : counter_register_range := counter_conf;
294 constant reg_address : unsigned(32 - 1 downto 0) := base_address + to_unsigned(4 * reg_index, 32);
295 constant reg_value : register_t := std_ulogic_vector(to_unsigned(value, register_width));
296 begin
297 write_bus(
298 net => net,
299 bus_handle => bus_handle,
300 address => std_logic_vector(reg_address),
301 data => reg_value
302 );
303 end procedure;
304
305 -- Write the 'conf' register.
306 procedure write_counter_conf(
307 signal net : inout network_t;
308 value : in counter_conf_t;
309 base_address : in unsigned(32 - 1 downto 0) := (others => '0');
310 bus_handle : in bus_master_t := register_bus_master
311 ) is
312 constant reg_index : counter_register_range := counter_conf;
313 constant reg_address : unsigned(32 - 1 downto 0) := base_address + to_unsigned(4 * reg_index, 32);
314 constant reg_value : register_t := to_slv(value);
315 begin
316 write_bus(
317 net => net,
318 bus_handle => bus_handle,
319 address => std_logic_vector(reg_address),
320 data => reg_value
321 );
322 end procedure;
323
324 -- Write the 'condition' field in the 'conf' register.
325 -- Will read-modify-write the register to set the field to the supplied 'value'.
326 procedure write_counter_conf_condition(
327 signal net : inout network_t;
328 value : in counter_conf_condition_t;
329 base_address : in unsigned(32 - 1 downto 0) := (others => '0');
330 bus_handle : in bus_master_t := register_bus_master
331 ) is
332 variable reg_value : counter_conf_t := counter_conf_init;
333 begin
334 read_counter_conf(
335 net => net,
336 value => reg_value,
337 base_address => base_address,
338 bus_handle => bus_handle
339 );
340 reg_value.condition := value;
341
342 write_counter_conf(
343 net => net,
344 value => reg_value,
345 base_address => base_address,
346 bus_handle => bus_handle
347 );
348 end procedure;
349
350 -- Write the 'increment' field in the 'conf' register.
351 -- Will read-modify-write the register to set the field to the supplied 'value'.
352 procedure write_counter_conf_increment(
353 signal net : inout network_t;
354 value : in counter_conf_increment_t;
355 base_address : in unsigned(32 - 1 downto 0) := (others => '0');
356 bus_handle : in bus_master_t := register_bus_master
357 ) is
358 variable reg_value : counter_conf_t := counter_conf_init;
359 begin
360 read_counter_conf(
361 net => net,
362 value => reg_value,
363 base_address => base_address,
364 bus_handle => bus_handle
365 );
366 reg_value.increment := value;
367
368 write_counter_conf(
369 net => net,
370 value => reg_value,
371 base_address => base_address,
372 bus_handle => bus_handle
373 );
374 end procedure;
375 -- ---------------------------------------------------------------------------
376
377 -- ---------------------------------------------------------------------------
378 -- Write the 'command' register as an 'integer'.
379 procedure write_counter_command(
380 signal net : inout network_t;
381 value : in integer;
382 base_address : in unsigned(32 - 1 downto 0) := (others => '0');
383 bus_handle : in bus_master_t := register_bus_master
384 ) is
385 constant reg_index : counter_register_range := counter_command;
386 constant reg_address : unsigned(32 - 1 downto 0) := base_address + to_unsigned(4 * reg_index, 32);
387 constant reg_value : register_t := std_ulogic_vector(to_unsigned(value, register_width));
388 begin
389 write_bus(
390 net => net,
391 bus_handle => bus_handle,
392 address => std_logic_vector(reg_address),
393 data => reg_value
394 );
395 end procedure;
396
397 -- Write the 'command' register.
398 procedure write_counter_command(
399 signal net : inout network_t;
400 value : in counter_command_t;
401 base_address : in unsigned(32 - 1 downto 0) := (others => '0');
402 bus_handle : in bus_master_t := register_bus_master
403 ) is
404 constant reg_index : counter_register_range := counter_command;
405 constant reg_address : unsigned(32 - 1 downto 0) := base_address + to_unsigned(4 * reg_index, 32);
406 constant reg_value : register_t := to_slv(value);
407 begin
408 write_bus(
409 net => net,
410 bus_handle => bus_handle,
411 address => std_logic_vector(reg_address),
412 data => reg_value
413 );
414 end procedure;
415
416 -- Write the 'start' field in the 'command' register.
417 -- Will write the whole register, with the field set to the
418 -- supplied 'value' and everything else set to default.
419 procedure write_counter_command_start(
420 signal net : inout network_t;
421 value : in std_ulogic;
422 base_address : in unsigned(32 - 1 downto 0) := (others => '0');
423 bus_handle : in bus_master_t := register_bus_master
424 ) is
425 variable reg_value : counter_command_t := counter_command_init;
426 begin
427 reg_value.start := value;
428
429 write_counter_command(
430 net => net,
431 value => reg_value,
432 base_address => base_address,
433 bus_handle => bus_handle
434 );
435 end procedure;
436
437 -- Write the 'stop' field in the 'command' register.
438 -- Will write the whole register, with the field set to the
439 -- supplied 'value' and everything else set to default.
440 procedure write_counter_command_stop(
441 signal net : inout network_t;
442 value : in std_ulogic;
443 base_address : in unsigned(32 - 1 downto 0) := (others => '0');
444 bus_handle : in bus_master_t := register_bus_master
445 ) is
446 variable reg_value : counter_command_t := counter_command_init;
447 begin
448 reg_value.stop := value;
449
450 write_counter_command(
451 net => net,
452 value => reg_value,
453 base_address => base_address,
454 bus_handle => bus_handle
455 );
456 end procedure;
457 -- ---------------------------------------------------------------------------
458
459 -- ---------------------------------------------------------------------------
460 -- Read the 'status' register as a plain 'register_t'.
461 procedure read_counter_status(
462 signal net : inout network_t;
463 value : out register_t;
464 base_address : in unsigned(32 - 1 downto 0) := (others => '0');
465 bus_handle : in bus_master_t := register_bus_master
466 ) is
467 constant reg_index : counter_register_range := counter_status;
468 constant reg_address : unsigned(32 - 1 downto 0) := base_address + to_unsigned(4 * reg_index, 32);
469 variable reg_value : register_t := (others => '0');
470 begin
471 read_bus(
472 net => net,
473 bus_handle => bus_handle,
474 address => std_logic_vector(reg_address),
475 data => reg_value
476 );
477 value := reg_value;
478 end procedure;
479
480 -- Read the 'status' register as an 'integer'.
481 procedure read_counter_status(
482 signal net : inout network_t;
483 value : out integer;
484 base_address : in unsigned(32 - 1 downto 0) := (others => '0');
485 bus_handle : in bus_master_t := register_bus_master
486 ) is
487 constant reg_index : counter_register_range := counter_status;
488 constant reg_address : unsigned(32 - 1 downto 0) := base_address + to_unsigned(4 * reg_index, 32);
489 variable reg_value : register_t := (others => '0');
490 begin
491 read_bus(
492 net => net,
493 bus_handle => bus_handle,
494 address => std_logic_vector(reg_address),
495 data => reg_value
496 );
497 value := to_integer(unsigned(reg_value));
498 end procedure;
499
500 -- Read the 'status' register.
501 procedure read_counter_status(
502 signal net : inout network_t;
503 value : out counter_status_t;
504 base_address : in unsigned(32 - 1 downto 0) := (others => '0');
505 bus_handle : in bus_master_t := register_bus_master
506 ) is
507 constant reg_index : counter_register_range := counter_status;
508 constant reg_address : unsigned(32 - 1 downto 0) := base_address + to_unsigned(4 * reg_index, 32);
509 variable reg_value : register_t := (others => '0');
510 begin
511 read_bus(
512 net => net,
513 bus_handle => bus_handle,
514 address => std_logic_vector(reg_address),
515 data => reg_value
516 );
517 value := to_counter_status(reg_value);
518 end procedure;
519
520 -- Read the 'enabled' field in the 'status' register.
521 procedure read_counter_status_enabled(
522 signal net : inout network_t;
523 value : out std_ulogic;
524 base_address : in unsigned(32 - 1 downto 0) := (others => '0');
525 bus_handle : in bus_master_t := register_bus_master
526 ) is
527 variable reg_value : counter_status_t := counter_status_init;
528 begin
529 read_counter_status(
530 net => net,
531 value => reg_value,
532 base_address => base_address,
533 bus_handle => bus_handle
534 );
535 value := reg_value.enabled;
536 end procedure;
537
538 -- Read the 'pulse_count' field in the 'status' register.
539 procedure read_counter_status_pulse_count(
540 signal net : inout network_t;
541 value : out counter_status_pulse_count_t;
542 base_address : in unsigned(32 - 1 downto 0) := (others => '0');
543 bus_handle : in bus_master_t := register_bus_master
544 ) is
545 variable reg_value : counter_status_t := counter_status_init;
546 begin
547 read_counter_status(
548 net => net,
549 value => reg_value,
550 base_address => base_address,
551 bus_handle => bus_handle
552 );
553 value := reg_value.pulse_count;
554 end procedure;
555 -- ---------------------------------------------------------------------------
556
557end 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 8.0.1-dev.
3-- Code generator VhdlSimulationCheckPackageGenerator version 1.2.1.
4-- Generated 2025-05-05 20:52 from file regs_counter.toml at Git commit f53f19ab11e0.
5-- Register hash e0b7d8e366d3777f3ef21d8e44540f964701e9be.
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 register_file;
21use register_file.register_file_pkg.register_t;
22use register_file.register_operations_pkg.register_bus_master;
23
24use work.counter_register_read_write_pkg.all;
25use work.counter_register_record_pkg.all;
26use work.counter_regs_pkg.all;
27
28
29package counter_register_check_pkg is
30
31 -- ---------------------------------------------------------------------------
32 -- Check that the current value of the 'conf' register
33 -- equals the given 'expected' value as a plain SLV casted to integer.
34 procedure check_counter_conf_equal(
35 signal net : inout network_t;
36 expected : in integer;
37 base_address : in unsigned(32 - 1 downto 0) := (others => '0');
38 bus_handle : in bus_master_t := register_bus_master;
39 message : in string := ""
40 );
41
42 -- Check that the current value of the 'conf' register
43 -- equals the given 'expected' value.
44 procedure check_counter_conf_equal(
45 signal net : inout network_t;
46 expected : in counter_conf_t;
47 base_address : in unsigned(32 - 1 downto 0) := (others => '0');
48 bus_handle : in bus_master_t := register_bus_master;
49 message : in string := ""
50 );
51
52 -- Check that the current value of the 'condition' field in the 'conf' register
53 -- equals the given 'expected' value.
54 procedure check_counter_conf_condition_equal(
55 signal net : inout network_t;
56 expected : in counter_conf_condition_t;
57 base_address : in unsigned(32 - 1 downto 0) := (others => '0');
58 bus_handle : in bus_master_t := register_bus_master;
59 message : in string := ""
60 );
61
62 -- Check that the current value of the 'increment' field in the 'conf' register
63 -- equals the given 'expected' value.
64 procedure check_counter_conf_increment_equal(
65 signal net : inout network_t;
66 expected : in counter_conf_increment_t;
67 base_address : in unsigned(32 - 1 downto 0) := (others => '0');
68 bus_handle : in bus_master_t := register_bus_master;
69 message : in string := ""
70 );
71 -- ---------------------------------------------------------------------------
72
73 -- ---------------------------------------------------------------------------
74 -- Check that the current value of the 'status' register
75 -- equals the given 'expected' value as a plain SLV casted to integer.
76 procedure check_counter_status_equal(
77 signal net : inout network_t;
78 expected : in integer;
79 base_address : in unsigned(32 - 1 downto 0) := (others => '0');
80 bus_handle : in bus_master_t := register_bus_master;
81 message : in string := ""
82 );
83
84 -- Check that the current value of the 'status' register
85 -- equals the given 'expected' value.
86 procedure check_counter_status_equal(
87 signal net : inout network_t;
88 expected : in counter_status_t;
89 base_address : in unsigned(32 - 1 downto 0) := (others => '0');
90 bus_handle : in bus_master_t := register_bus_master;
91 message : in string := ""
92 );
93
94 -- Check that the current value of the 'enabled' field in the 'status' register
95 -- equals the given 'expected' value.
96 procedure check_counter_status_enabled_equal(
97 signal net : inout network_t;
98 expected : in std_ulogic;
99 base_address : in unsigned(32 - 1 downto 0) := (others => '0');
100 bus_handle : in bus_master_t := register_bus_master;
101 message : in string := ""
102 );
103
104 -- Check that the current value of the 'pulse_count' field in the 'status' register
105 -- equals the given 'expected' value.
106 procedure check_counter_status_pulse_count_equal(
107 signal net : inout network_t;
108 expected : in counter_status_pulse_count_t;
109 base_address : in unsigned(32 - 1 downto 0) := (others => '0');
110 bus_handle : in bus_master_t := register_bus_master;
111 message : in string := ""
112 );
113 -- ---------------------------------------------------------------------------
114
115end package;
116
117package body counter_register_check_pkg is
118
119 -- ---------------------------------------------------------------------------
120 -- Check that the current value of the 'conf' register
121 -- equals the given 'expected' value as a plain SLV casted to integer.
122 procedure check_counter_conf_equal(
123 signal net : inout network_t;
124 expected : in integer;
125 base_address : in unsigned(32 - 1 downto 0) := (others => '0');
126 bus_handle : in bus_master_t := register_bus_master;
127 message : in string := ""
128 ) is
129 constant register_array_message : string := "";
130 function base_address_message return string is
131 begin
132 if base_address /= 0 then
133 return " (at base address " & hex_image(std_logic_vector(base_address)) & ")";
134 end if;
135
136 return "";
137 end function;
138 constant base_message : string := (
139 "Checking the 'conf' register"
140 & register_array_message
141 & base_address_message
142 & "."
143 );
144 function get_message return string is
145 begin
146 if message = "" then
147 return base_message;
148 end if;
149
150 return base_message & " " & message & ".";
151 end function;
152
153 variable got : integer;
154 begin
155 read_counter_conf(
156 net => net,
157 value => got,
158 base_address => base_address,
159 bus_handle => bus_handle
160 );
161
162 check_equal(got=>got, expected=>expected, msg=>get_message);
163 end procedure;
164
165 -- Check that the current value of the 'conf' register
166 -- equals the given 'expected' value.
167 procedure check_counter_conf_equal(
168 signal net : inout network_t;
169 expected : in counter_conf_t;
170 base_address : in unsigned(32 - 1 downto 0) := (others => '0');
171 bus_handle : in bus_master_t := register_bus_master;
172 message : in string := ""
173 ) is
174 constant register_array_message : string := "";
175 function base_address_message return string is
176 begin
177 if base_address /= 0 then
178 return " (at base address " & hex_image(std_logic_vector(base_address)) & ")";
179 end if;
180
181 return "";
182 end function;
183 constant base_message : string := (
184 "Checking the 'conf' register"
185 & register_array_message
186 & base_address_message
187 & "."
188 );
189 function get_message return string is
190 begin
191 if message = "" then
192 return base_message;
193 end if;
194
195 return base_message & " " & message & ".";
196 end function;
197
198 variable got : counter_conf_t;
199 begin
200 read_counter_conf(
201 net => net,
202 value => got,
203 base_address => base_address,
204 bus_handle => bus_handle
205 );
206
207 if got /= expected then
208 failing_check(
209 checker => default_checker,
210 msg => p_std_msg(
211 check_result => "Equality check failed",
212 msg => get_message,
213 ctx => (
214 "Got " & to_string(to_slv(got)) & ". Expected " & to_string(to_slv(expected)) & "."
215 )
216 )
217 );
218 end if;
219 end procedure;
220
221 -- Check that the current value of the 'condition' field in the 'conf' register
222 -- equals the given 'expected' value.
223 procedure check_counter_conf_condition_equal(
224 signal net : inout network_t;
225 expected : in counter_conf_condition_t;
226 base_address : in unsigned(32 - 1 downto 0) := (others => '0');
227 bus_handle : in bus_master_t := register_bus_master;
228 message : in string := ""
229 ) is
230 constant register_array_message : string := "";
231 function base_address_message return string is
232 begin
233 if base_address /= 0 then
234 return " (at base address " & hex_image(std_logic_vector(base_address)) & ")";
235 end if;
236
237 return "";
238 end function;
239 constant base_message : string := (
240 "Checking the 'condition' field in the 'conf' register"
241 & register_array_message
242 & base_address_message
243 & "."
244 );
245 function get_message return string is
246 begin
247 if message = "" then
248 return base_message;
249 end if;
250
251 return base_message & " " & message & ".";
252 end function;
253
254 variable got_reg : counter_conf_t := counter_conf_init;
255 variable got : counter_conf_condition_t := counter_conf_condition_init;
256 begin
257 read_counter_conf(
258 net => net,
259 value => got_reg,
260 base_address => base_address,
261 bus_handle => bus_handle
262 );
263 got := got_reg.condition;
264
265 if got /= expected then
266 failing_check(
267 checker => default_checker,
268 msg => p_std_msg(
269 check_result => "Equality check failed",
270 msg => get_message,
271 ctx => (
272 "Got " & to_string(got) & "."
273 & " Expected " & to_string(expected) & "."
274 )
275 )
276 );
277 end if;
278 end procedure;
279
280 -- Check that the current value of the 'increment' field in the 'conf' register
281 -- equals the given 'expected' value.
282 procedure check_counter_conf_increment_equal(
283 signal net : inout network_t;
284 expected : in counter_conf_increment_t;
285 base_address : in unsigned(32 - 1 downto 0) := (others => '0');
286 bus_handle : in bus_master_t := register_bus_master;
287 message : in string := ""
288 ) is
289 constant register_array_message : string := "";
290 function base_address_message return string is
291 begin
292 if base_address /= 0 then
293 return " (at base address " & hex_image(std_logic_vector(base_address)) & ")";
294 end if;
295
296 return "";
297 end function;
298 constant base_message : string := (
299 "Checking the 'increment' field in the 'conf' register"
300 & register_array_message
301 & base_address_message
302 & "."
303 );
304 function get_message return string is
305 begin
306 if message = "" then
307 return base_message;
308 end if;
309
310 return base_message & " " & message & ".";
311 end function;
312
313 variable got_reg : counter_conf_t := counter_conf_init;
314 variable got : counter_conf_increment_t := counter_conf_increment_init;
315 begin
316 read_counter_conf(
317 net => net,
318 value => got_reg,
319 base_address => base_address,
320 bus_handle => bus_handle
321 );
322 got := got_reg.increment;
323
324 check_equal(got=>got, expected=>expected, msg=>get_message);
325 end procedure;
326 -- ---------------------------------------------------------------------------
327
328 -- ---------------------------------------------------------------------------
329 -- Check that the current value of the 'status' register
330 -- equals the given 'expected' value as a plain SLV casted to integer.
331 procedure check_counter_status_equal(
332 signal net : inout network_t;
333 expected : in integer;
334 base_address : in unsigned(32 - 1 downto 0) := (others => '0');
335 bus_handle : in bus_master_t := register_bus_master;
336 message : in string := ""
337 ) is
338 constant register_array_message : string := "";
339 function base_address_message return string is
340 begin
341 if base_address /= 0 then
342 return " (at base address " & hex_image(std_logic_vector(base_address)) & ")";
343 end if;
344
345 return "";
346 end function;
347 constant base_message : string := (
348 "Checking the 'status' register"
349 & register_array_message
350 & base_address_message
351 & "."
352 );
353 function get_message return string is
354 begin
355 if message = "" then
356 return base_message;
357 end if;
358
359 return base_message & " " & message & ".";
360 end function;
361
362 variable got : integer;
363 begin
364 read_counter_status(
365 net => net,
366 value => got,
367 base_address => base_address,
368 bus_handle => bus_handle
369 );
370
371 check_equal(got=>got, expected=>expected, msg=>get_message);
372 end procedure;
373
374 -- Check that the current value of the 'status' register
375 -- equals the given 'expected' value.
376 procedure check_counter_status_equal(
377 signal net : inout network_t;
378 expected : in counter_status_t;
379 base_address : in unsigned(32 - 1 downto 0) := (others => '0');
380 bus_handle : in bus_master_t := register_bus_master;
381 message : in string := ""
382 ) is
383 constant register_array_message : string := "";
384 function base_address_message return string is
385 begin
386 if base_address /= 0 then
387 return " (at base address " & hex_image(std_logic_vector(base_address)) & ")";
388 end if;
389
390 return "";
391 end function;
392 constant base_message : string := (
393 "Checking the 'status' register"
394 & register_array_message
395 & base_address_message
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
407 variable got : counter_status_t;
408 begin
409 read_counter_status(
410 net => net,
411 value => got,
412 base_address => base_address,
413 bus_handle => bus_handle
414 );
415
416 if got /= expected then
417 failing_check(
418 checker => default_checker,
419 msg => p_std_msg(
420 check_result => "Equality check failed",
421 msg => get_message,
422 ctx => (
423 "Got " & to_string(to_slv(got)) & ". Expected " & to_string(to_slv(expected)) & "."
424 )
425 )
426 );
427 end if;
428 end procedure;
429
430 -- Check that the current value of the 'enabled' field in the 'status' register
431 -- equals the given 'expected' value.
432 procedure check_counter_status_enabled_equal(
433 signal net : inout network_t;
434 expected : in std_ulogic;
435 base_address : in unsigned(32 - 1 downto 0) := (others => '0');
436 bus_handle : in bus_master_t := register_bus_master;
437 message : in string := ""
438 ) is
439 constant register_array_message : string := "";
440 function base_address_message return string is
441 begin
442 if base_address /= 0 then
443 return " (at base address " & hex_image(std_logic_vector(base_address)) & ")";
444 end if;
445
446 return "";
447 end function;
448 constant base_message : string := (
449 "Checking the 'enabled' field in the 'status' register"
450 & register_array_message
451 & base_address_message
452 & "."
453 );
454 function get_message return string is
455 begin
456 if message = "" then
457 return base_message;
458 end if;
459
460 return base_message & " " & message & ".";
461 end function;
462
463 variable got_reg : counter_status_t := counter_status_init;
464 variable got : std_ulogic := counter_status_enabled_init;
465 begin
466 read_counter_status(
467 net => net,
468 value => got_reg,
469 base_address => base_address,
470 bus_handle => bus_handle
471 );
472 got := got_reg.enabled;
473
474 check_equal(got=>got, expected=>expected, msg=>get_message);
475 end procedure;
476
477 -- Check that the current value of the 'pulse_count' field in the 'status' register
478 -- equals the given 'expected' value.
479 procedure check_counter_status_pulse_count_equal(
480 signal net : inout network_t;
481 expected : in counter_status_pulse_count_t;
482 base_address : in unsigned(32 - 1 downto 0) := (others => '0');
483 bus_handle : in bus_master_t := register_bus_master;
484 message : in string := ""
485 ) is
486 constant register_array_message : string := "";
487 function base_address_message return string is
488 begin
489 if base_address /= 0 then
490 return " (at base address " & hex_image(std_logic_vector(base_address)) & ")";
491 end if;
492
493 return "";
494 end function;
495 constant base_message : string := (
496 "Checking the 'pulse_count' field in the 'status' register"
497 & register_array_message
498 & base_address_message
499 & "."
500 );
501 function get_message return string is
502 begin
503 if message = "" then
504 return base_message;
505 end if;
506
507 return base_message & " " & message & ".";
508 end function;
509
510 variable got_reg : counter_status_t := counter_status_init;
511 variable got : counter_status_pulse_count_t := counter_status_pulse_count_init;
512 begin
513 read_counter_status(
514 net => net,
515 value => got_reg,
516 base_address => base_address,
517 bus_handle => bus_handle
518 );
519 got := got_reg.pulse_count;
520
521 check_equal(got=>got, expected=>expected, msg=>get_message);
522 end procedure;
523 -- ---------------------------------------------------------------------------
524
525end 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 8.0.1-dev.
3-- Code generator VhdlSimulationWaitUntilPackageGenerator version 1.0.2.
4-- Generated 2025-05-05 20:52 from file regs_counter.toml at Git commit f53f19ab11e0.
5-- Register hash e0b7d8e366d3777f3ef21d8e44540f964701e9be.
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 register_file;
21use register_file.register_file_pkg.register_t;
22use register_file.register_operations_pkg.register_bus_master;
23
24use work.counter_regs_pkg.all;
25use work.counter_register_record_pkg.all;
26
27
28package counter_register_wait_until_pkg is
29
30 -- ---------------------------------------------------------------------------
31 -- Wait until the 'conf' register equals the given 'value'.
32 procedure wait_until_counter_conf_equals(
33 signal net : inout network_t;
34 value : in counter_conf_t;
35 base_address : in unsigned(32 - 1 downto 0) := (others => '0');
36 bus_handle : in bus_master_t := register_bus_master;
37 timeout : delay_length := max_timeout;
38 message : string := ""
39 );
40
41 -- Wait until the 'condition' field in the 'conf' register equals the given 'value'.
42 procedure wait_until_counter_conf_condition_equals(
43 signal net : inout network_t;
44 value : in counter_conf_condition_t;
45 base_address : in unsigned(32 - 1 downto 0) := (others => '0');
46 bus_handle : in bus_master_t := register_bus_master;
47 timeout : delay_length := max_timeout;
48 message : string := ""
49 );
50
51 -- Wait until the 'increment' field in the 'conf' register equals the given 'value'.
52 procedure wait_until_counter_conf_increment_equals(
53 signal net : inout network_t;
54 value : in counter_conf_increment_t;
55 base_address : in unsigned(32 - 1 downto 0) := (others => '0');
56 bus_handle : in bus_master_t := register_bus_master;
57 timeout : delay_length := max_timeout;
58 message : string := ""
59 );
60 -- ---------------------------------------------------------------------------
61
62 -- ---------------------------------------------------------------------------
63 -- Wait until the 'status' register equals the given 'value'.
64 procedure wait_until_counter_status_equals(
65 signal net : inout network_t;
66 value : in counter_status_t;
67 base_address : in unsigned(32 - 1 downto 0) := (others => '0');
68 bus_handle : in bus_master_t := register_bus_master;
69 timeout : delay_length := max_timeout;
70 message : string := ""
71 );
72
73 -- Wait until the 'enabled' field in the 'status' register equals the given 'value'.
74 procedure wait_until_counter_status_enabled_equals(
75 signal net : inout network_t;
76 value : in std_ulogic;
77 base_address : in unsigned(32 - 1 downto 0) := (others => '0');
78 bus_handle : in bus_master_t := register_bus_master;
79 timeout : delay_length := max_timeout;
80 message : string := ""
81 );
82
83 -- Wait until the 'pulse_count' field in the 'status' register equals the given 'value'.
84 procedure wait_until_counter_status_pulse_count_equals(
85 signal net : inout network_t;
86 value : in counter_status_pulse_count_t;
87 base_address : in unsigned(32 - 1 downto 0) := (others => '0');
88 bus_handle : in bus_master_t := register_bus_master;
89 timeout : delay_length := max_timeout;
90 message : string := ""
91 );
92 -- ---------------------------------------------------------------------------
93
94end package;
95
96package body counter_register_wait_until_pkg is
97
98 -- ---------------------------------------------------------------------------
99 -- Wait until the 'conf' register equals the given 'value'.
100 procedure wait_until_counter_conf_equals(
101 signal net : inout network_t;
102 value : in counter_conf_t;
103 base_address : in unsigned(32 - 1 downto 0) := (others => '0');
104 bus_handle : in bus_master_t := register_bus_master;
105 timeout : delay_length := max_timeout;
106 message : string := ""
107 ) is
108 constant reg_value : register_t := to_slv(value);
109
110 constant reg_index : counter_register_range := counter_conf;
111 constant reg_address : unsigned(32 - 1 downto 0) := base_address + to_unsigned(4 * reg_index, 32);
112
113 constant register_array_message : string := "";
114 function base_address_message return string is
115 begin
116 if base_address /= 0 then
117 return " (at base address " & hex_image(std_logic_vector(base_address)) & ")";
118 end if;
119
120 return "";
121 end function;
122 constant base_message : string := (
123 "Timeout while waiting for the 'conf' register"
124 & register_array_message
125 & base_address_message
126 & " to equal the given value: "
127 & to_string(reg_value)
128 & "."
129 );
130 function get_message return string is
131 begin
132 if message = "" then
133 return base_message;
134 end if;
135
136 return base_message & " " & message & ".";
137 end function;
138 begin
139 wait_until_read_equals(
140 net => net,
141 bus_handle => bus_handle,
142 addr => std_ulogic_vector(reg_address),
143 value => reg_value,
144 timeout => timeout,
145 msg => get_message
146 );
147 end procedure;
148
149 -- Wait until the 'condition' field in the 'conf' register equals the given 'value'.
150 procedure wait_until_counter_conf_condition_equals(
151 signal net : inout network_t;
152 value : in counter_conf_condition_t;
153 base_address : in unsigned(32 - 1 downto 0) := (others => '0');
154 bus_handle : in bus_master_t := register_bus_master;
155 timeout : delay_length := max_timeout;
156 message : string := ""
157 ) is
158 constant reg_value : register_t := (
159 counter_conf_condition => to_slv(value),
160 others => '-'
161 );
162
163 constant reg_index : counter_register_range := counter_conf;
164 constant reg_address : unsigned(32 - 1 downto 0) := base_address + to_unsigned(4 * reg_index, 32);
165
166 constant register_array_message : string := "";
167 function base_address_message return string is
168 begin
169 if base_address /= 0 then
170 return " (at base address " & hex_image(std_logic_vector(base_address)) & ")";
171 end if;
172
173 return "";
174 end function;
175 constant base_message : string := (
176 "Timeout while waiting for the 'condition' field in the 'conf' register"
177 & register_array_message
178 & base_address_message
179 & " to equal the given value: "
180 & to_string(reg_value)
181 & "."
182 );
183 function get_message return string is
184 begin
185 if message = "" then
186 return base_message;
187 end if;
188
189 return base_message & " " & message & ".";
190 end function;
191 begin
192 wait_until_read_equals(
193 net => net,
194 bus_handle => bus_handle,
195 addr => std_ulogic_vector(reg_address),
196 value => reg_value,
197 timeout => timeout,
198 msg => get_message
199 );
200 end procedure;
201
202 -- Wait until the 'increment' field in the 'conf' register equals the given 'value'.
203 procedure wait_until_counter_conf_increment_equals(
204 signal net : inout network_t;
205 value : in counter_conf_increment_t;
206 base_address : in unsigned(32 - 1 downto 0) := (others => '0');
207 bus_handle : in bus_master_t := register_bus_master;
208 timeout : delay_length := max_timeout;
209 message : string := ""
210 ) is
211 constant reg_value : register_t := (
212 counter_conf_increment => to_counter_conf_increment_slv(value),
213 others => '-'
214 );
215
216 constant reg_index : counter_register_range := counter_conf;
217 constant reg_address : unsigned(32 - 1 downto 0) := base_address + to_unsigned(4 * reg_index, 32);
218
219 constant register_array_message : string := "";
220 function base_address_message return string is
221 begin
222 if base_address /= 0 then
223 return " (at base address " & hex_image(std_logic_vector(base_address)) & ")";
224 end if;
225
226 return "";
227 end function;
228 constant base_message : string := (
229 "Timeout while waiting for the 'increment' field in the 'conf' register"
230 & register_array_message
231 & base_address_message
232 & " to equal the given value: "
233 & to_string(reg_value)
234 & "."
235 );
236 function get_message return string is
237 begin
238 if message = "" then
239 return base_message;
240 end if;
241
242 return base_message & " " & message & ".";
243 end function;
244 begin
245 wait_until_read_equals(
246 net => net,
247 bus_handle => bus_handle,
248 addr => std_ulogic_vector(reg_address),
249 value => reg_value,
250 timeout => timeout,
251 msg => get_message
252 );
253 end procedure;
254 -- ---------------------------------------------------------------------------
255
256 -- ---------------------------------------------------------------------------
257 -- Wait until the 'status' register equals the given 'value'.
258 procedure wait_until_counter_status_equals(
259 signal net : inout network_t;
260 value : in counter_status_t;
261 base_address : in unsigned(32 - 1 downto 0) := (others => '0');
262 bus_handle : in bus_master_t := register_bus_master;
263 timeout : delay_length := max_timeout;
264 message : string := ""
265 ) is
266 constant reg_value : register_t := to_slv(value);
267
268 constant reg_index : counter_register_range := counter_status;
269 constant reg_address : unsigned(32 - 1 downto 0) := base_address + to_unsigned(4 * reg_index, 32);
270
271 constant register_array_message : string := "";
272 function base_address_message return string is
273 begin
274 if base_address /= 0 then
275 return " (at base address " & hex_image(std_logic_vector(base_address)) & ")";
276 end if;
277
278 return "";
279 end function;
280 constant base_message : string := (
281 "Timeout while waiting for the 'status' register"
282 & register_array_message
283 & base_address_message
284 & " to equal the given value: "
285 & to_string(reg_value)
286 & "."
287 );
288 function get_message return string is
289 begin
290 if message = "" then
291 return base_message;
292 end if;
293
294 return base_message & " " & message & ".";
295 end function;
296 begin
297 wait_until_read_equals(
298 net => net,
299 bus_handle => bus_handle,
300 addr => std_ulogic_vector(reg_address),
301 value => reg_value,
302 timeout => timeout,
303 msg => get_message
304 );
305 end procedure;
306
307 -- Wait until the 'enabled' field in the 'status' register equals the given 'value'.
308 procedure wait_until_counter_status_enabled_equals(
309 signal net : inout network_t;
310 value : in std_ulogic;
311 base_address : in unsigned(32 - 1 downto 0) := (others => '0');
312 bus_handle : in bus_master_t := register_bus_master;
313 timeout : delay_length := max_timeout;
314 message : string := ""
315 ) is
316 constant reg_value : register_t := (
317 counter_status_enabled => value,
318 others => '-'
319 );
320
321 constant reg_index : counter_register_range := counter_status;
322 constant reg_address : unsigned(32 - 1 downto 0) := base_address + to_unsigned(4 * reg_index, 32);
323
324 constant register_array_message : string := "";
325 function base_address_message return string is
326 begin
327 if base_address /= 0 then
328 return " (at base address " & hex_image(std_logic_vector(base_address)) & ")";
329 end if;
330
331 return "";
332 end function;
333 constant base_message : string := (
334 "Timeout while waiting for the 'enabled' field in the 'status' register"
335 & register_array_message
336 & base_address_message
337 & " to equal the given value: "
338 & to_string(reg_value)
339 & "."
340 );
341 function get_message return string is
342 begin
343 if message = "" then
344 return base_message;
345 end if;
346
347 return base_message & " " & message & ".";
348 end function;
349 begin
350 wait_until_read_equals(
351 net => net,
352 bus_handle => bus_handle,
353 addr => std_ulogic_vector(reg_address),
354 value => reg_value,
355 timeout => timeout,
356 msg => get_message
357 );
358 end procedure;
359
360 -- Wait until the 'pulse_count' field in the 'status' register equals the given 'value'.
361 procedure wait_until_counter_status_pulse_count_equals(
362 signal net : inout network_t;
363 value : in counter_status_pulse_count_t;
364 base_address : in unsigned(32 - 1 downto 0) := (others => '0');
365 bus_handle : in bus_master_t := register_bus_master;
366 timeout : delay_length := max_timeout;
367 message : string := ""
368 ) is
369 constant reg_value : register_t := (
370 counter_status_pulse_count => to_counter_status_pulse_count_slv(value),
371 others => '-'
372 );
373
374 constant reg_index : counter_register_range := counter_status;
375 constant reg_address : unsigned(32 - 1 downto 0) := base_address + to_unsigned(4 * reg_index, 32);
376
377 constant register_array_message : string := "";
378 function base_address_message return string is
379 begin
380 if base_address /= 0 then
381 return " (at base address " & hex_image(std_logic_vector(base_address)) & ")";
382 end if;
383
384 return "";
385 end function;
386 constant base_message : string := (
387 "Timeout while waiting for the 'pulse_count' field in the 'status' register"
388 & register_array_message
389 & base_address_message
390 & " to equal the given value: "
391 & to_string(reg_value)
392 & "."
393 );
394 function get_message return string is
395 begin
396 if message = "" then
397 return base_message;
398 end if;
399
400 return base_message & " " & message & ".";
401 end function;
402 begin
403 wait_until_read_equals(
404 net => net,
405 bus_handle => bus_handle,
406 addr => std_ulogic_vector(reg_address),
407 value => reg_value,
408 timeout => timeout,
409 msg => get_message
410 );
411 end procedure;
412 -- ---------------------------------------------------------------------------
413
414end 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
Generated VHDL code depends on files from hdl-modules version 6.2.0 or greater:
axi_lite_pkg.vhd and axi_lite_register_file.vhd in a library called
axi_lite
.register_file_pkg.vhd in a library called
register_file
.
The simulation code is furthermore dependent on the file
register_operations_pkg.vhd
in the library register_file
, and access to VUnit’s
VHDL libraries.
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.