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_reg_file_inst : entity work.counter_reg_file
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 reg_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-- This file is automatically generated by hdl-registers version 6.1.1-dev.
2-- Code generator VhdlRegisterPackageGenerator version 1.0.0.
3-- Generated 2024-12-01 20:51 from file regs_counter.toml at commit 2ca830a4377d1e32.
4-- Register hash 49f02a8daa9dd4bc3dadeb2a1cfd61dcc38c3864.
5
6library ieee;
7use ieee.std_logic_1164.all;
8use ieee.numeric_std.all;
9use ieee.fixed_pkg.all;
10
11library reg_file;
12use reg_file.reg_file_pkg.all;
13
14
15package counter_regs_pkg is
16
17 -- ---------------------------------------------------------------------------
18 -- The valid range of register indexes.
19 subtype counter_reg_range is natural range 0 to 2;
20
21 -- Register indexes, within the list of registers.
22 constant counter_config : natural := 0;
23 constant counter_command : natural := 1;
24 constant counter_status : natural := 2;
25
26 -- Declare 'reg_map' and 'regs_init' constants here but define them in body (deferred constants).
27 -- So that functions have been elaborated when they are called.
28 -- Needed for ModelSim compilation to pass.
29
30 -- To be used as the 'regs' generic of 'axi_lite_reg_file.vhd'.
31 constant counter_reg_map : reg_definition_vec_t(counter_reg_range);
32
33 -- To be used for the 'regs_up' and 'regs_down' ports of 'axi_lite_reg_file.vhd'.
34 subtype counter_regs_t is reg_vec_t(counter_reg_range);
35 -- To be used as the 'default_values' generic of 'axi_lite_reg_file.vhd'.
36 constant counter_regs_init : counter_regs_t;
37
38 -- To be used for the 'reg_was_read' and 'reg_was_written' ports of 'axi_lite_reg_file.vhd'.
39 subtype counter_reg_was_accessed_t is std_ulogic_vector(counter_reg_range);
40
41 -- -----------------------------------------------------------------------------
42 -- Fields in the 'config' register.
43 -- Range of the 'condition' field.
44 subtype counter_config_condition is natural range 1 downto 0;
45 -- Width of the 'condition' field.
46 constant counter_config_condition_width : positive := 2;
47 -- Type for the 'condition' field.
48 type counter_config_condition_t is (
49 condition_clock_cycles,
50 condition_clock_cycles_with_enable,
51 condition_enable_edges
52 );
53 -- Default value of the 'condition' field.
54 constant counter_config_condition_init : counter_config_condition_t := condition_clock_cycles;
55 -- Type for the 'condition' field as an SLV.
56 subtype counter_config_condition_slv_t is std_ulogic_vector(1 downto 0);
57 -- Cast a 'condition' field value to SLV.
58 function to_slv(data : counter_config_condition_t) return counter_config_condition_slv_t;
59 -- Get a 'condition' field value from a register value.
60 function to_counter_config_condition(data : reg_t) return counter_config_condition_t;
61
62 -- Range of the 'increment' field.
63 subtype counter_config_increment is natural range 5 downto 2;
64 -- Width of the 'increment' field.
65 constant counter_config_increment_width : positive := 4;
66 -- Type for the 'increment' field.
67 subtype counter_config_increment_t is integer range 0 to 15;
68 -- Default value of the 'increment' field.
69 constant counter_config_increment_init : counter_config_increment_t := 0;
70 -- Type for the 'increment' field as an SLV.
71 subtype counter_config_increment_slv_t is std_ulogic_vector(3 downto 0);
72 -- Cast a 'increment' field value to SLV.
73 function to_counter_config_increment_slv(data : counter_config_increment_t) return counter_config_increment_slv_t;
74 -- Get a 'increment' field value from a register value.
75 function to_counter_config_increment(data : reg_t) return counter_config_increment_t;
76
77 -- -----------------------------------------------------------------------------
78 -- Fields in the 'command' register.
79 -- Range of the 'start' field.
80 constant counter_command_start : natural := 0;
81 -- Default value of the 'start' field.
82 constant counter_command_start_init : std_ulogic := '0';
83
84 -- Range of the 'stop' field.
85 constant counter_command_stop : natural := 1;
86 -- Default value of the 'stop' field.
87 constant counter_command_stop_init : std_ulogic := '0';
88
89 -- -----------------------------------------------------------------------------
90 -- Fields in the 'status' register.
91 -- Range of the 'enabled' field.
92 constant counter_status_enabled : natural := 0;
93 -- Default value of the 'enabled' field.
94 constant counter_status_enabled_init : std_ulogic := '0';
95
96 -- Range of the 'pulse_count' field.
97 subtype counter_status_pulse_count is natural range 8 downto 1;
98 -- Width of the 'pulse_count' field.
99 constant counter_status_pulse_count_width : positive := 8;
100 -- Type for the 'pulse_count' field.
101 subtype counter_status_pulse_count_t is integer range 0 to 255;
102 -- Default value of the 'pulse_count' field.
103 constant counter_status_pulse_count_init : counter_status_pulse_count_t := 0;
104 -- Type for the 'pulse_count' field as an SLV.
105 subtype counter_status_pulse_count_slv_t is std_ulogic_vector(7 downto 0);
106 -- Cast a 'pulse_count' field value to SLV.
107 function to_counter_status_pulse_count_slv(data : counter_status_pulse_count_t) return counter_status_pulse_count_slv_t;
108 -- Get a 'pulse_count' field value from a register value.
109 function to_counter_status_pulse_count(data : reg_t) return counter_status_pulse_count_t;
110
111end package;
112
113package body counter_regs_pkg is
114
115 constant counter_reg_map : reg_definition_vec_t(counter_reg_range) := (
116 0 => (idx => counter_config, reg_type => r_w),
117 1 => (idx => counter_command, reg_type => wpulse),
118 2 => (idx => counter_status, reg_type => r)
119 );
120
121 constant counter_regs_init : counter_regs_t := (
122 0 => "00000000000000000000000000000000",
123 1 => "00000000000000000000000000000000",
124 2 => "00000000000000000000000000000000"
125 );
126
127 -- Cast a 'condition' field value to SLV.
128 function to_slv(data : counter_config_condition_t) return counter_config_condition_slv_t is
129 constant data_int : natural := counter_config_condition_t'pos(data);
130 constant result : counter_config_condition_slv_t := std_ulogic_vector(
131 to_unsigned(data_int, counter_config_condition_width)
132 );
133 begin
134 return result;
135 end function;
136
137 -- Get a 'condition' field value from a register value.
138 function to_counter_config_condition(data : reg_t) return counter_config_condition_t is
139 constant field_slv : counter_config_condition_slv_t := data(counter_config_condition);
140 constant field_int : natural := to_integer(unsigned(field_slv));
141 constant result : counter_config_condition_t := counter_config_condition_t'val(field_int);
142 begin
143 return result;
144 end function;
145
146 -- Cast a 'increment' field value to SLV.
147 function to_counter_config_increment_slv(data : counter_config_increment_t) return counter_config_increment_slv_t is
148 constant result : counter_config_increment_slv_t := std_ulogic_vector(to_unsigned(data, counter_config_increment_width));
149 begin
150 return result;
151 end function;
152
153 -- Get a 'increment' field value from a register value.
154 function to_counter_config_increment(data : reg_t) return counter_config_increment_t is
155 constant result : integer := to_integer(unsigned(data(counter_config_increment)));
156 begin
157 return result;
158 end function;
159
160 -- Cast a 'pulse_count' field value to SLV.
161 function to_counter_status_pulse_count_slv(data : counter_status_pulse_count_t) return counter_status_pulse_count_slv_t is
162 constant result : counter_status_pulse_count_slv_t := std_ulogic_vector(to_unsigned(data, counter_status_pulse_count_width));
163 begin
164 return result;
165 end function;
166
167 -- Get a 'pulse_count' field value from a register value.
168 function to_counter_status_pulse_count(data : reg_t) return counter_status_pulse_count_t is
169 constant result : integer := to_integer(unsigned(data(counter_status_pulse_count)));
170 begin
171 return result;
172 end function;
173
174end 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-- This file is automatically generated by hdl-registers version 6.1.1-dev.
2-- Code generator VhdlRecordPackageGenerator version 1.0.0.
3-- Generated 2024-12-01 20:51 from file regs_counter.toml at commit 2ca830a4377d1e32.
4-- Register hash 49f02a8daa9dd4bc3dadeb2a1cfd61dcc38c3864.
5
6library ieee;
7use ieee.fixed_pkg.all;
8use ieee.std_logic_1164.all;
9use ieee.numeric_std.all;
10
11library reg_file;
12use reg_file.reg_file_pkg.reg_t;
13
14use work.counter_regs_pkg.all;
15
16
17package counter_register_record_pkg is
18
19 -- -----------------------------------------------------------------------------
20 -- Record with correctly-typed members for each field in each register.
21 -- Fields in the 'config' register as a record.
22 type counter_config_t is record
23 condition : counter_config_condition_t;
24 increment : counter_config_increment_t;
25 end record;
26 -- Default value for the 'config' register as a record.
27 constant counter_config_init : counter_config_t := (
28 condition => counter_config_condition_init,
29 increment => counter_config_increment_init
30 );
31 -- Convert a record of the 'config' register to SLV.
32 function to_slv(data : counter_config_t) return reg_t;
33 -- Convert an SLV register value to the record for the 'config' register.
34 function to_counter_config(data : reg_t) return counter_config_t;
35
36 -- Fields in the 'command' register as a record.
37 type counter_command_t is record
38 start : std_ulogic;
39 stop : std_ulogic;
40 end record;
41 -- Default value for the 'command' register as a record.
42 constant counter_command_init : counter_command_t := (
43 start => counter_command_start_init,
44 stop => counter_command_stop_init
45 );
46 -- Convert a record of the 'command' register to SLV.
47 function to_slv(data : counter_command_t) return reg_t;
48 -- Convert an SLV register value to the record for the 'command' register.
49 function to_counter_command(data : reg_t) return counter_command_t;
50
51 -- Fields in the 'status' register as a record.
52 type counter_status_t is record
53 enabled : std_ulogic;
54 pulse_count : counter_status_pulse_count_t;
55 end record;
56 -- Default value for the 'status' register as a record.
57 constant counter_status_init : counter_status_t := (
58 enabled => counter_status_enabled_init,
59 pulse_count => counter_status_pulse_count_init
60 );
61 -- Convert a record of the 'status' register to SLV.
62 function to_slv(data : counter_status_t) return reg_t;
63 -- Convert an SLV register value to the record for the 'status' register.
64 function to_counter_status(data : reg_t) return counter_status_t;
65
66 -- -----------------------------------------------------------------------------
67 -- Below is a record with correctly typed and ranged members for all registers, register arrays
68 -- and fields that are in the 'up' direction.
69 -- Record with everything in the 'up' direction.
70 type counter_regs_up_t is record
71 status : counter_status_t;
72 end record;
73 -- Default value of the above record.
74 constant counter_regs_up_init : counter_regs_up_t := (
75 status => counter_status_init
76 );
77 -- Convert record with everything in the 'up' direction to SLV register list.
78 function to_slv(data : counter_regs_up_t) return counter_regs_t;
79
80 -- -----------------------------------------------------------------------------
81 -- Below is a record with correctly typed and ranged members for all registers, register arrays
82 -- and fields that are in the 'down' direction.
83 -- Record with everything in the 'down' direction.
84 type counter_regs_down_t is record
85 config : counter_config_t;
86 command : counter_command_t;
87 end record;
88 -- Default value of the above record.
89 constant counter_regs_down_init : counter_regs_down_t := (
90 config => counter_config_init,
91 command => counter_command_init
92 );
93 -- Convert SLV register list to record with everything in the 'down' direction.
94 function to_counter_regs_down(data : counter_regs_t) return counter_regs_down_t;
95
96 -- ---------------------------------------------------------------------------
97 -- Below is a record with a status bit for each readable register in the register map.
98 -- It can be used for the 'reg_was_read' port of a register file wrapper.
99 -- Combined status mask record for all readable register.
100 type counter_reg_was_read_t is record
101 config : std_ulogic;
102 status : std_ulogic;
103 end record;
104 -- Default value for the above record.
105 constant counter_reg_was_read_init : counter_reg_was_read_t := (
106 others => '0'
107 );
108 -- Convert an SLV 'reg_was_read' from generic register file to the record above.
109 function to_counter_reg_was_read(
110 data : counter_reg_was_accessed_t
111 ) return counter_reg_was_read_t;
112
113 -- ---------------------------------------------------------------------------
114 -- Below is a record with a status bit for each writeable register in the register map.
115 -- It can be used for the 'reg_was_written' port of a register file wrapper.
116 -- Combined status mask record for all writeable register.
117 type counter_reg_was_written_t is record
118 config : std_ulogic;
119 command : std_ulogic;
120 end record;
121 -- Default value for the above record.
122 constant counter_reg_was_written_init : counter_reg_was_written_t := (
123 others => '0'
124 );
125 -- Convert an SLV 'reg_was_written' from generic register file to the record above.
126 function to_counter_reg_was_written(
127 data : counter_reg_was_accessed_t
128 ) return counter_reg_was_written_t;
129
130end package;
131
132package body counter_register_record_pkg is
133
134 function to_slv(data : counter_config_t) return reg_t is
135 variable result : reg_t := (others => '-');
136 begin
137 result(counter_config_condition) := to_slv(data.condition);
138 result(counter_config_increment) := to_counter_config_increment_slv(data.increment);
139
140 return result;
141 end function;
142
143 function to_counter_config(data : reg_t) return counter_config_t is
144 variable result : counter_config_t := counter_config_init;
145 begin
146 result.condition := to_counter_config_condition(data);
147 result.increment := to_counter_config_increment(data);
148
149 return result;
150 end function;
151
152 function to_slv(data : counter_command_t) return reg_t is
153 variable result : reg_t := (others => '-');
154 begin
155 result(counter_command_start) := data.start;
156 result(counter_command_stop) := data.stop;
157
158 return result;
159 end function;
160
161 function to_counter_command(data : reg_t) return counter_command_t is
162 variable result : counter_command_t := counter_command_init;
163 begin
164 result.start := data(counter_command_start);
165 result.stop := data(counter_command_stop);
166
167 return result;
168 end function;
169
170 function to_slv(data : counter_status_t) return reg_t is
171 variable result : reg_t := (others => '-');
172 begin
173 result(counter_status_enabled) := data.enabled;
174 result(counter_status_pulse_count) := to_counter_status_pulse_count_slv(data.pulse_count);
175
176 return result;
177 end function;
178
179 function to_counter_status(data : reg_t) return counter_status_t is
180 variable result : counter_status_t := counter_status_init;
181 begin
182 result.enabled := data(counter_status_enabled);
183 result.pulse_count := to_counter_status_pulse_count(data);
184
185 return result;
186 end function;
187
188 function to_slv(data : counter_regs_up_t) return counter_regs_t is
189 variable result : counter_regs_t := counter_regs_init;
190 begin
191 result(counter_status) := to_slv(data.status);
192
193 return result;
194 end function;
195
196 function to_counter_regs_down(data : counter_regs_t) return counter_regs_down_t is
197 variable result : counter_regs_down_t := counter_regs_down_init;
198 begin
199 result.config := to_counter_config(data(counter_config));
200 result.command := to_counter_command(data(counter_command));
201
202 return result;
203 end function;
204
205 function to_counter_reg_was_read(
206 data : counter_reg_was_accessed_t
207 ) return counter_reg_was_read_t is
208 variable result : counter_reg_was_read_t := counter_reg_was_read_init;
209 begin
210 result.config := data(counter_config);
211 result.status := data(counter_status);
212
213 return result;
214 end function;
215
216 function to_counter_reg_was_written(
217 data : counter_reg_was_accessed_t
218 ) return counter_reg_was_written_t is
219 variable result : counter_reg_was_written_t := counter_reg_was_written_init;
220 begin
221 result.config := data(counter_config);
222 result.command := data(counter_command);
223
224 return result;
225 end function;
226
227end 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-- AXI-Lite register file for the 'counter' module registers.
3--
4-- Is a wrapper around the generic AXI-Lite register file from hdl-modules:
5-- * https://hdl-modules.com/modules/reg_file/reg_file.html#axi-lite-reg-file-vhd
6-- * https://github.com/hdl-modules/hdl-modules/blob/main/modules/reg_file/src/axi_lite_reg_file.vhd
7--
8-- Sets correct generics, and performs conversion to the easy-to-use register record types.
9-- -----------------------------------------------------------------------------
10-- This file is automatically generated by hdl-registers version 6.1.1-dev.
11-- Code generator VhdlAxiLiteWrapperGenerator version 1.0.0.
12-- Generated 2024-12-01 20:51 from file regs_counter.toml at commit 2ca830a4377d1e32.
13-- Register hash 49f02a8daa9dd4bc3dadeb2a1cfd61dcc38c3864.
14-- -----------------------------------------------------------------------------
15
16library ieee;
17use ieee.std_logic_1164.all;
18
19library axi_lite;
20use axi_lite.axi_lite_pkg.all;
21
22library reg_file;
23use reg_file.reg_file_pkg.all;
24
25use work.counter_regs_pkg.all;
26use work.counter_register_record_pkg.all;
27
28
29entity counter_reg_file is
30 port (
31 clk : in std_ulogic;
32 --# {}
33 --# Register control bus.
34 axi_lite_m2s : in axi_lite_m2s_t;
35 axi_lite_s2m : out axi_lite_s2m_t := axi_lite_s2m_init;
36 --# {}
37 -- Register values.
38 regs_up : in counter_regs_up_t := counter_regs_up_init;
39 regs_down : out counter_regs_down_t := counter_regs_down_init;
40 --# {}
41 -- Each bit is pulsed for one cycle when the corresponding register is read/written.
42 reg_was_read : out counter_reg_was_read_t := counter_reg_was_read_init;
43 reg_was_written : out counter_reg_was_written_t := counter_reg_was_written_init
44 );
45end entity;
46
47architecture a of counter_reg_file is
48
49 signal regs_up_slv, regs_down_slv : counter_regs_t := counter_regs_init;
50
51 signal reg_was_read_slv, reg_was_written_slv : counter_reg_was_accessed_t := (
52 others => '0'
53 );
54
55begin
56
57 ------------------------------------------------------------------------------
58 -- Instantiate the generic AXI-Lite register file from
59 -- * https://hdl-modules.com/modules/reg_file/reg_file.html#axi-lite-reg-file-vhd
60 -- * https://github.com/hdl-modules/hdl-modules/blob/main/modules/reg_file/src/axi_lite_reg_file.vhd
61 axi_lite_reg_file_inst : entity reg_file.axi_lite_reg_file
62 generic map (
63 regs => counter_reg_map,
64 default_values => counter_regs_init
65 )
66 port map(
67 clk => clk,
68 --
69 axi_lite_m2s => axi_lite_m2s,
70 axi_lite_s2m => axi_lite_s2m,
71 --
72 regs_up => regs_up_slv,
73 regs_down => regs_down_slv,
74 --
75 reg_was_read => reg_was_read_slv,
76 reg_was_written => reg_was_written_slv
77 );
78
79
80 ------------------------------------------------------------------------------
81 -- Combinatorially convert the register record to a list of SLV values that can be handled
82 -- by the generic register file implementation.
83 assign_regs_up : process(regs_up)
84 begin
85 regs_up_slv <= to_slv(regs_up);
86 end process;
87
88
89 ------------------------------------------------------------------------------
90 -- Combinatorially convert the list of SLV values from the generic register file into the record
91 -- we want to use in our application.
92 assign_regs_down : process(regs_down_slv)
93 begin
94 regs_down <= to_counter_regs_down(regs_down_slv);
95 end process;
96
97
98 ------------------------------------------------------------------------------
99 -- Combinatorially convert status mask to a record where only the applicable registers are present.
100 assign_reg_was_read : process(reg_was_read_slv)
101 begin
102 reg_was_read <= to_counter_reg_was_read(reg_was_read_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_written : process(reg_was_written_slv)
109 begin
110 reg_was_written <= to_counter_reg_was_written(reg_was_written_slv);
111 end process;
112
113end 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-- This file is automatically generated by hdl-registers version 6.1.1-dev.
2-- Code generator VhdlSimulationReadWritePackageGenerator version 1.1.0.
3-- Generated 2024-12-01 20:51 from file regs_counter.toml at commit 2ca830a4377d1e32.
4-- Register hash 49f02a8daa9dd4bc3dadeb2a1cfd61dcc38c3864.
5
6library ieee;
7use ieee.numeric_std.all;
8use ieee.std_logic_1164.all;
9
10library vunit_lib;
11use vunit_lib.bus_master_pkg.bus_master_t;
12use vunit_lib.bus_master_pkg.read_bus;
13use vunit_lib.bus_master_pkg.write_bus;
14use vunit_lib.com_types_pkg.network_t;
15
16library common;
17use common.addr_pkg.addr_t;
18use common.addr_pkg.addr_width;
19
20library reg_file;
21use reg_file.reg_file_pkg.reg_t;
22use reg_file.reg_file_pkg.reg_width;
23use reg_file.reg_operations_pkg.regs_bus_master;
24
25use work.counter_regs_pkg.all;
26use work.counter_register_record_pkg.all;
27
28
29package counter_register_read_write_pkg is
30
31 -- ---------------------------------------------------------------------------
32 -- Read the 'config' register as a plain 'reg_t'.
33 procedure read_counter_config(
34 signal net : inout network_t;
35 value : out reg_t;
36 base_address : in addr_t := (others => '0');
37 bus_handle : in bus_master_t := regs_bus_master
38 );
39
40 -- Read the 'config' register as an 'integer'.
41 procedure read_counter_config(
42 signal net : inout network_t;
43 value : out integer;
44 base_address : in addr_t := (others => '0');
45 bus_handle : in bus_master_t := regs_bus_master
46 );
47
48 -- Read the 'config' register.
49 procedure read_counter_config(
50 signal net : inout network_t;
51 value : out counter_config_t;
52 base_address : in addr_t := (others => '0');
53 bus_handle : in bus_master_t := regs_bus_master
54 );
55
56 -- Read the 'condition' field in the 'config' register.
57 procedure read_counter_config_condition(
58 signal net : inout network_t;
59 value : out counter_config_condition_t;
60 base_address : in addr_t := (others => '0');
61 bus_handle : in bus_master_t := regs_bus_master
62 );
63
64 -- Read the 'increment' field in the 'config' register.
65 procedure read_counter_config_increment(
66 signal net : inout network_t;
67 value : out counter_config_increment_t;
68 base_address : in addr_t := (others => '0');
69 bus_handle : in bus_master_t := regs_bus_master
70 );
71
72 -- Write the 'config' register as an 'integer'.
73 procedure write_counter_config(
74 signal net : inout network_t;
75 value : in integer;
76 base_address : in addr_t := (others => '0');
77 bus_handle : in bus_master_t := regs_bus_master
78 );
79
80 -- Write the 'config' register.
81 procedure write_counter_config(
82 signal net : inout network_t;
83 value : in counter_config_t;
84 base_address : in addr_t := (others => '0');
85 bus_handle : in bus_master_t := regs_bus_master
86 );
87
88 -- Write the 'condition' field in the 'config' register.
89 -- Will read-modify-write the register to set the field to the supplied 'value'.
90 procedure write_counter_config_condition(
91 signal net : inout network_t;
92 value : in counter_config_condition_t;
93 base_address : in addr_t := (others => '0');
94 bus_handle : in bus_master_t := regs_bus_master
95 );
96
97 -- Write the 'increment' field in the 'config' register.
98 -- Will read-modify-write the register to set the field to the supplied 'value'.
99 procedure write_counter_config_increment(
100 signal net : inout network_t;
101 value : in counter_config_increment_t;
102 base_address : in addr_t := (others => '0');
103 bus_handle : in bus_master_t := regs_bus_master
104 );
105 -- ---------------------------------------------------------------------------
106
107 -- ---------------------------------------------------------------------------
108 -- Write the 'command' register as an 'integer'.
109 procedure write_counter_command(
110 signal net : inout network_t;
111 value : in integer;
112 base_address : in addr_t := (others => '0');
113 bus_handle : in bus_master_t := regs_bus_master
114 );
115
116 -- Write the 'command' register.
117 procedure write_counter_command(
118 signal net : inout network_t;
119 value : in counter_command_t;
120 base_address : in addr_t := (others => '0');
121 bus_handle : in bus_master_t := regs_bus_master
122 );
123
124 -- Write the 'start' field in the 'command' register.
125 -- Will write the whole register, with the field set to the
126 -- supplied 'value' and everything else set to default.
127 procedure write_counter_command_start(
128 signal net : inout network_t;
129 value : in std_ulogic;
130 base_address : in addr_t := (others => '0');
131 bus_handle : in bus_master_t := regs_bus_master
132 );
133
134 -- Write the 'stop' field in the 'command' register.
135 -- Will write the whole register, with the field set to the
136 -- supplied 'value' and everything else set to default.
137 procedure write_counter_command_stop(
138 signal net : inout network_t;
139 value : in std_ulogic;
140 base_address : in addr_t := (others => '0');
141 bus_handle : in bus_master_t := regs_bus_master
142 );
143 -- ---------------------------------------------------------------------------
144
145 -- ---------------------------------------------------------------------------
146 -- Read the 'status' register as a plain 'reg_t'.
147 procedure read_counter_status(
148 signal net : inout network_t;
149 value : out reg_t;
150 base_address : in addr_t := (others => '0');
151 bus_handle : in bus_master_t := regs_bus_master
152 );
153
154 -- Read the 'status' register as an 'integer'.
155 procedure read_counter_status(
156 signal net : inout network_t;
157 value : out integer;
158 base_address : in addr_t := (others => '0');
159 bus_handle : in bus_master_t := regs_bus_master
160 );
161
162 -- Read the 'status' register.
163 procedure read_counter_status(
164 signal net : inout network_t;
165 value : out counter_status_t;
166 base_address : in addr_t := (others => '0');
167 bus_handle : in bus_master_t := regs_bus_master
168 );
169
170 -- Read the 'enabled' field in the 'status' register.
171 procedure read_counter_status_enabled(
172 signal net : inout network_t;
173 value : out std_ulogic;
174 base_address : in addr_t := (others => '0');
175 bus_handle : in bus_master_t := regs_bus_master
176 );
177
178 -- Read the 'pulse_count' field in the 'status' register.
179 procedure read_counter_status_pulse_count(
180 signal net : inout network_t;
181 value : out counter_status_pulse_count_t;
182 base_address : in addr_t := (others => '0');
183 bus_handle : in bus_master_t := regs_bus_master
184 );
185 -- ---------------------------------------------------------------------------
186
187end package;
188
189package body counter_register_read_write_pkg is
190
191 -- ---------------------------------------------------------------------------
192 -- Read the 'config' register as a plain 'reg_t'.
193 procedure read_counter_config(
194 signal net : inout network_t;
195 value : out reg_t;
196 base_address : in addr_t := (others => '0');
197 bus_handle : in bus_master_t := regs_bus_master
198 ) is
199 constant reg_index : counter_reg_range := counter_config;
200 constant reg_address : addr_t := base_address + to_unsigned(4 * reg_index, addr_width);
201 variable reg_value : reg_t := (others => '0');
202 begin
203 read_bus(
204 net => net,
205 bus_handle => bus_handle,
206 address => std_logic_vector(reg_address),
207 data => reg_value
208 );
209 value := reg_value;
210 end procedure;
211
212 -- Read the 'config' register as an 'integer'.
213 procedure read_counter_config(
214 signal net : inout network_t;
215 value : out integer;
216 base_address : in addr_t := (others => '0');
217 bus_handle : in bus_master_t := regs_bus_master
218 ) is
219 constant reg_index : counter_reg_range := counter_config;
220 constant reg_address : addr_t := base_address + to_unsigned(4 * reg_index, addr_width);
221 variable reg_value : reg_t := (others => '0');
222 begin
223 read_bus(
224 net => net,
225 bus_handle => bus_handle,
226 address => std_logic_vector(reg_address),
227 data => reg_value
228 );
229 value := to_integer(unsigned(reg_value));
230 end procedure;
231
232 -- Read the 'config' register.
233 procedure read_counter_config(
234 signal net : inout network_t;
235 value : out counter_config_t;
236 base_address : in addr_t := (others => '0');
237 bus_handle : in bus_master_t := regs_bus_master
238 ) is
239 constant reg_index : counter_reg_range := counter_config;
240 constant reg_address : addr_t := base_address + to_unsigned(4 * reg_index, addr_width);
241 variable reg_value : reg_t := (others => '0');
242 begin
243 read_bus(
244 net => net,
245 bus_handle => bus_handle,
246 address => std_logic_vector(reg_address),
247 data => reg_value
248 );
249 value := to_counter_config(reg_value);
250 end procedure;
251
252 -- Read the 'condition' field in the 'config' register.
253 procedure read_counter_config_condition(
254 signal net : inout network_t;
255 value : out counter_config_condition_t;
256 base_address : in addr_t := (others => '0');
257 bus_handle : in bus_master_t := regs_bus_master
258 ) is
259 variable reg_value : counter_config_t := counter_config_init;
260 begin
261 read_counter_config(
262 net => net,
263 value => reg_value,
264 base_address => base_address,
265 bus_handle => bus_handle
266 );
267 value := reg_value.condition;
268 end procedure;
269
270 -- Read the 'increment' field in the 'config' register.
271 procedure read_counter_config_increment(
272 signal net : inout network_t;
273 value : out counter_config_increment_t;
274 base_address : in addr_t := (others => '0');
275 bus_handle : in bus_master_t := regs_bus_master
276 ) is
277 variable reg_value : counter_config_t := counter_config_init;
278 begin
279 read_counter_config(
280 net => net,
281 value => reg_value,
282 base_address => base_address,
283 bus_handle => bus_handle
284 );
285 value := reg_value.increment;
286 end procedure;
287
288 -- Write the 'config' register as an 'integer'.
289 procedure write_counter_config(
290 signal net : inout network_t;
291 value : in integer;
292 base_address : in addr_t := (others => '0');
293 bus_handle : in bus_master_t := regs_bus_master
294 ) is
295 constant reg_index : counter_reg_range := counter_config;
296 constant reg_address : addr_t := base_address + to_unsigned(4 * reg_index, addr_width);
297 constant reg_value : reg_t := std_ulogic_vector(to_unsigned(value, reg_width));
298 begin
299 write_bus(
300 net => net,
301 bus_handle => bus_handle,
302 address => std_logic_vector(reg_address),
303 data => reg_value
304 );
305 end procedure;
306
307 -- Write the 'config' register.
308 procedure write_counter_config(
309 signal net : inout network_t;
310 value : in counter_config_t;
311 base_address : in addr_t := (others => '0');
312 bus_handle : in bus_master_t := regs_bus_master
313 ) is
314 constant reg_index : counter_reg_range := counter_config;
315 constant reg_address : addr_t := base_address + to_unsigned(4 * reg_index, addr_width);
316 constant reg_value : reg_t := to_slv(value);
317 begin
318 write_bus(
319 net => net,
320 bus_handle => bus_handle,
321 address => std_logic_vector(reg_address),
322 data => reg_value
323 );
324 end procedure;
325
326 -- Write the 'condition' field in the 'config' register.
327 -- Will read-modify-write the register to set the field to the supplied 'value'.
328 procedure write_counter_config_condition(
329 signal net : inout network_t;
330 value : in counter_config_condition_t;
331 base_address : in addr_t := (others => '0');
332 bus_handle : in bus_master_t := regs_bus_master
333 ) is
334 variable reg_value : counter_config_t := counter_config_init;
335 begin
336 read_counter_config(
337 net => net,
338 value => reg_value,
339 base_address => base_address,
340 bus_handle => bus_handle
341 );
342 reg_value.condition := value;
343
344 write_counter_config(
345 net => net,
346 value => reg_value,
347 base_address => base_address,
348 bus_handle => bus_handle
349 );
350 end procedure;
351
352 -- Write the 'increment' field in the 'config' register.
353 -- Will read-modify-write the register to set the field to the supplied 'value'.
354 procedure write_counter_config_increment(
355 signal net : inout network_t;
356 value : in counter_config_increment_t;
357 base_address : in addr_t := (others => '0');
358 bus_handle : in bus_master_t := regs_bus_master
359 ) is
360 variable reg_value : counter_config_t := counter_config_init;
361 begin
362 read_counter_config(
363 net => net,
364 value => reg_value,
365 base_address => base_address,
366 bus_handle => bus_handle
367 );
368 reg_value.increment := value;
369
370 write_counter_config(
371 net => net,
372 value => reg_value,
373 base_address => base_address,
374 bus_handle => bus_handle
375 );
376 end procedure;
377 -- ---------------------------------------------------------------------------
378
379 -- ---------------------------------------------------------------------------
380 -- Write the 'command' register as an 'integer'.
381 procedure write_counter_command(
382 signal net : inout network_t;
383 value : in integer;
384 base_address : in addr_t := (others => '0');
385 bus_handle : in bus_master_t := regs_bus_master
386 ) is
387 constant reg_index : counter_reg_range := counter_command;
388 constant reg_address : addr_t := base_address + to_unsigned(4 * reg_index, addr_width);
389 constant reg_value : reg_t := std_ulogic_vector(to_unsigned(value, reg_width));
390 begin
391 write_bus(
392 net => net,
393 bus_handle => bus_handle,
394 address => std_logic_vector(reg_address),
395 data => reg_value
396 );
397 end procedure;
398
399 -- Write the 'command' register.
400 procedure write_counter_command(
401 signal net : inout network_t;
402 value : in counter_command_t;
403 base_address : in addr_t := (others => '0');
404 bus_handle : in bus_master_t := regs_bus_master
405 ) is
406 constant reg_index : counter_reg_range := counter_command;
407 constant reg_address : addr_t := base_address + to_unsigned(4 * reg_index, addr_width);
408 constant reg_value : reg_t := to_slv(value);
409 begin
410 write_bus(
411 net => net,
412 bus_handle => bus_handle,
413 address => std_logic_vector(reg_address),
414 data => reg_value
415 );
416 end procedure;
417
418 -- Write the 'start' field in the 'command' register.
419 -- Will write the whole register, with the field set to the
420 -- supplied 'value' and everything else set to default.
421 procedure write_counter_command_start(
422 signal net : inout network_t;
423 value : in std_ulogic;
424 base_address : in addr_t := (others => '0');
425 bus_handle : in bus_master_t := regs_bus_master
426 ) is
427 variable reg_value : counter_command_t := counter_command_init;
428 begin
429 reg_value.start := value;
430
431 write_counter_command(
432 net => net,
433 value => reg_value,
434 base_address => base_address,
435 bus_handle => bus_handle
436 );
437 end procedure;
438
439 -- Write the 'stop' field in the 'command' register.
440 -- Will write the whole register, with the field set to the
441 -- supplied 'value' and everything else set to default.
442 procedure write_counter_command_stop(
443 signal net : inout network_t;
444 value : in std_ulogic;
445 base_address : in addr_t := (others => '0');
446 bus_handle : in bus_master_t := regs_bus_master
447 ) is
448 variable reg_value : counter_command_t := counter_command_init;
449 begin
450 reg_value.stop := value;
451
452 write_counter_command(
453 net => net,
454 value => reg_value,
455 base_address => base_address,
456 bus_handle => bus_handle
457 );
458 end procedure;
459 -- ---------------------------------------------------------------------------
460
461 -- ---------------------------------------------------------------------------
462 -- Read the 'status' register as a plain 'reg_t'.
463 procedure read_counter_status(
464 signal net : inout network_t;
465 value : out reg_t;
466 base_address : in addr_t := (others => '0');
467 bus_handle : in bus_master_t := regs_bus_master
468 ) is
469 constant reg_index : counter_reg_range := counter_status;
470 constant reg_address : addr_t := base_address + to_unsigned(4 * reg_index, addr_width);
471 variable reg_value : reg_t := (others => '0');
472 begin
473 read_bus(
474 net => net,
475 bus_handle => bus_handle,
476 address => std_logic_vector(reg_address),
477 data => reg_value
478 );
479 value := reg_value;
480 end procedure;
481
482 -- Read the 'status' register as an 'integer'.
483 procedure read_counter_status(
484 signal net : inout network_t;
485 value : out integer;
486 base_address : in addr_t := (others => '0');
487 bus_handle : in bus_master_t := regs_bus_master
488 ) is
489 constant reg_index : counter_reg_range := counter_status;
490 constant reg_address : addr_t := base_address + to_unsigned(4 * reg_index, addr_width);
491 variable reg_value : reg_t := (others => '0');
492 begin
493 read_bus(
494 net => net,
495 bus_handle => bus_handle,
496 address => std_logic_vector(reg_address),
497 data => reg_value
498 );
499 value := to_integer(unsigned(reg_value));
500 end procedure;
501
502 -- Read the 'status' register.
503 procedure read_counter_status(
504 signal net : inout network_t;
505 value : out counter_status_t;
506 base_address : in addr_t := (others => '0');
507 bus_handle : in bus_master_t := regs_bus_master
508 ) is
509 constant reg_index : counter_reg_range := counter_status;
510 constant reg_address : addr_t := base_address + to_unsigned(4 * reg_index, addr_width);
511 variable reg_value : reg_t := (others => '0');
512 begin
513 read_bus(
514 net => net,
515 bus_handle => bus_handle,
516 address => std_logic_vector(reg_address),
517 data => reg_value
518 );
519 value := to_counter_status(reg_value);
520 end procedure;
521
522 -- Read the 'enabled' field in the 'status' register.
523 procedure read_counter_status_enabled(
524 signal net : inout network_t;
525 value : out std_ulogic;
526 base_address : in addr_t := (others => '0');
527 bus_handle : in bus_master_t := regs_bus_master
528 ) is
529 variable reg_value : counter_status_t := counter_status_init;
530 begin
531 read_counter_status(
532 net => net,
533 value => reg_value,
534 base_address => base_address,
535 bus_handle => bus_handle
536 );
537 value := reg_value.enabled;
538 end procedure;
539
540 -- Read the 'pulse_count' field in the 'status' register.
541 procedure read_counter_status_pulse_count(
542 signal net : inout network_t;
543 value : out counter_status_pulse_count_t;
544 base_address : in addr_t := (others => '0');
545 bus_handle : in bus_master_t := regs_bus_master
546 ) is
547 variable reg_value : counter_status_t := counter_status_init;
548 begin
549 read_counter_status(
550 net => net,
551 value => reg_value,
552 base_address => base_address,
553 bus_handle => bus_handle
554 );
555 value := reg_value.pulse_count;
556 end procedure;
557 -- ---------------------------------------------------------------------------
558
559end 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-- This file is automatically generated by hdl-registers version 6.1.1-dev.
2-- Code generator VhdlSimulationCheckPackageGenerator version 1.2.0.
3-- Generated 2024-12-01 20:51 from file regs_counter.toml at commit 2ca830a4377d1e32.
4-- Register hash 49f02a8daa9dd4bc3dadeb2a1cfd61dcc38c3864.
5
6library ieee;
7use ieee.fixed_pkg.all;
8use ieee.numeric_std.all;
9use ieee.std_logic_1164.all;
10
11library vunit_lib;
12use vunit_lib.bus_master_pkg.bus_master_t;
13use vunit_lib.check_pkg.all;
14use vunit_lib.checker_pkg.all;
15use vunit_lib.com_types_pkg.network_t;
16use vunit_lib.string_ops.hex_image;
17
18library common;
19use common.addr_pkg.addr_t;
20
21library reg_file;
22use reg_file.reg_file_pkg.reg_t;
23use reg_file.reg_operations_pkg.regs_bus_master;
24
25use work.counter_register_read_write_pkg.all;
26use work.counter_register_record_pkg.all;
27use work.counter_regs_pkg.all;
28
29
30package counter_register_check_pkg is
31
32 -- ---------------------------------------------------------------------------
33 -- Check that the current value of the 'config' register
34 -- equals the given 'expected' value as a plain SLV casted to integer.
35 procedure check_counter_config_equal(
36 signal net : inout network_t;
37 expected : in integer;
38 base_address : in addr_t := (others => '0');
39 bus_handle : in bus_master_t := regs_bus_master;
40 message : in string := ""
41 );
42
43 -- Check that the current value of the 'config' register
44 -- equals the given 'expected' value.
45 procedure check_counter_config_equal(
46 signal net : inout network_t;
47 expected : in counter_config_t;
48 base_address : in addr_t := (others => '0');
49 bus_handle : in bus_master_t := regs_bus_master;
50 message : in string := ""
51 );
52
53 -- Check that the current value of the 'condition' field in the 'config' register
54 -- equals the given 'expected' value.
55 procedure check_counter_config_condition_equal(
56 signal net : inout network_t;
57 expected : in counter_config_condition_t;
58 base_address : in addr_t := (others => '0');
59 bus_handle : in bus_master_t := regs_bus_master;
60 message : in string := ""
61 );
62
63 -- Check that the current value of the 'increment' field in the 'config' register
64 -- equals the given 'expected' value.
65 procedure check_counter_config_increment_equal(
66 signal net : inout network_t;
67 expected : in counter_config_increment_t;
68 base_address : in addr_t := (others => '0');
69 bus_handle : in bus_master_t := regs_bus_master;
70 message : in string := ""
71 );
72 -- ---------------------------------------------------------------------------
73
74 -- ---------------------------------------------------------------------------
75 -- Check that the current value of the 'status' register
76 -- equals the given 'expected' value as a plain SLV casted to integer.
77 procedure check_counter_status_equal(
78 signal net : inout network_t;
79 expected : in integer;
80 base_address : in addr_t := (others => '0');
81 bus_handle : in bus_master_t := regs_bus_master;
82 message : in string := ""
83 );
84
85 -- Check that the current value of the 'status' register
86 -- equals the given 'expected' value.
87 procedure check_counter_status_equal(
88 signal net : inout network_t;
89 expected : in counter_status_t;
90 base_address : in addr_t := (others => '0');
91 bus_handle : in bus_master_t := regs_bus_master;
92 message : in string := ""
93 );
94
95 -- Check that the current value of the 'enabled' field in the 'status' register
96 -- equals the given 'expected' value.
97 procedure check_counter_status_enabled_equal(
98 signal net : inout network_t;
99 expected : in std_ulogic;
100 base_address : in addr_t := (others => '0');
101 bus_handle : in bus_master_t := regs_bus_master;
102 message : in string := ""
103 );
104
105 -- Check that the current value of the 'pulse_count' field in the 'status' register
106 -- equals the given 'expected' value.
107 procedure check_counter_status_pulse_count_equal(
108 signal net : inout network_t;
109 expected : in counter_status_pulse_count_t;
110 base_address : in addr_t := (others => '0');
111 bus_handle : in bus_master_t := regs_bus_master;
112 message : in string := ""
113 );
114 -- ---------------------------------------------------------------------------
115
116end package;
117
118package body counter_register_check_pkg is
119
120 -- ---------------------------------------------------------------------------
121 -- Check that the current value of the 'config' register
122 -- equals the given 'expected' value as a plain SLV casted to integer.
123 procedure check_counter_config_equal(
124 signal net : inout network_t;
125 expected : in integer;
126 base_address : in addr_t := (others => '0');
127 bus_handle : in bus_master_t := regs_bus_master;
128 message : in string := ""
129 ) is
130 constant register_array_message : string := "";
131 function base_address_message return string is
132 begin
133 if base_address /= 0 then
134 return " (at base address " & hex_image(std_logic_vector(base_address)) & ")";
135 end if;
136
137 return "";
138 end function;
139 constant base_message : string := (
140 "Checking the 'config' register"
141 & register_array_message
142 & base_address_message
143 & "."
144 );
145 function get_message return string is
146 begin
147 if message = "" then
148 return base_message;
149 end if;
150
151 return base_message & " " & message & ".";
152 end function;
153
154 variable got : integer;
155 begin
156 read_counter_config(
157 net => net,
158 value => got,
159 base_address => base_address,
160 bus_handle => bus_handle
161 );
162
163 check_equal(got=>got, expected=>expected, msg=>get_message);
164 end procedure;
165
166 -- Check that the current value of the 'config' register
167 -- equals the given 'expected' value.
168 procedure check_counter_config_equal(
169 signal net : inout network_t;
170 expected : in counter_config_t;
171 base_address : in addr_t := (others => '0');
172 bus_handle : in bus_master_t := regs_bus_master;
173 message : in string := ""
174 ) is
175 constant register_array_message : string := "";
176 function base_address_message return string is
177 begin
178 if base_address /= 0 then
179 return " (at base address " & hex_image(std_logic_vector(base_address)) & ")";
180 end if;
181
182 return "";
183 end function;
184 constant base_message : string := (
185 "Checking the 'config' register"
186 & register_array_message
187 & base_address_message
188 & "."
189 );
190 function get_message return string is
191 begin
192 if message = "" then
193 return base_message;
194 end if;
195
196 return base_message & " " & message & ".";
197 end function;
198
199 variable got : counter_config_t;
200 begin
201 read_counter_config(
202 net => net,
203 value => got,
204 base_address => base_address,
205 bus_handle => bus_handle
206 );
207
208 if got /= expected then
209 failing_check(
210 checker => default_checker,
211 msg => p_std_msg(
212 check_result => "Equality check failed",
213 msg => get_message,
214 ctx => (
215 "Got " & to_string(to_slv(got)) & ". Expected " & to_string(to_slv(expected)) & "."
216 )
217 )
218 );
219 end if;
220 end procedure;
221
222 -- Check that the current value of the 'condition' field in the 'config' register
223 -- equals the given 'expected' value.
224 procedure check_counter_config_condition_equal(
225 signal net : inout network_t;
226 expected : in counter_config_condition_t;
227 base_address : in addr_t := (others => '0');
228 bus_handle : in bus_master_t := regs_bus_master;
229 message : in string := ""
230 ) is
231 constant register_array_message : string := "";
232 function base_address_message return string is
233 begin
234 if base_address /= 0 then
235 return " (at base address " & hex_image(std_logic_vector(base_address)) & ")";
236 end if;
237
238 return "";
239 end function;
240 constant base_message : string := (
241 "Checking the 'condition' field in the 'config' register"
242 & register_array_message
243 & base_address_message
244 & "."
245 );
246 function get_message return string is
247 begin
248 if message = "" then
249 return base_message;
250 end if;
251
252 return base_message & " " & message & ".";
253 end function;
254
255 variable got_reg : counter_config_t := counter_config_init;
256 variable got : counter_config_condition_t := counter_config_condition_init;
257 begin
258 read_counter_config(
259 net => net,
260 value => got_reg,
261 base_address => base_address,
262 bus_handle => bus_handle
263 );
264 got := got_reg.condition;
265
266 if got /= expected then
267 failing_check(
268 checker => default_checker,
269 msg => p_std_msg(
270 check_result => "Equality check failed",
271 msg => get_message,
272 ctx => (
273 "Got " & to_string(got) & "."
274 & " Expected " & to_string(expected) & "."
275 )
276 )
277 );
278 end if;
279 end procedure;
280
281 -- Check that the current value of the 'increment' field in the 'config' register
282 -- equals the given 'expected' value.
283 procedure check_counter_config_increment_equal(
284 signal net : inout network_t;
285 expected : in counter_config_increment_t;
286 base_address : in addr_t := (others => '0');
287 bus_handle : in bus_master_t := regs_bus_master;
288 message : in string := ""
289 ) is
290 constant register_array_message : string := "";
291 function base_address_message return string is
292 begin
293 if base_address /= 0 then
294 return " (at base address " & hex_image(std_logic_vector(base_address)) & ")";
295 end if;
296
297 return "";
298 end function;
299 constant base_message : string := (
300 "Checking the 'increment' field in the 'config' register"
301 & register_array_message
302 & base_address_message
303 & "."
304 );
305 function get_message return string is
306 begin
307 if message = "" then
308 return base_message;
309 end if;
310
311 return base_message & " " & message & ".";
312 end function;
313
314 variable got_reg : counter_config_t := counter_config_init;
315 variable got : counter_config_increment_t := counter_config_increment_init;
316 begin
317 read_counter_config(
318 net => net,
319 value => got_reg,
320 base_address => base_address,
321 bus_handle => bus_handle
322 );
323 got := got_reg.increment;
324
325 check_equal(got=>got, expected=>expected, msg=>get_message);
326 end procedure;
327 -- ---------------------------------------------------------------------------
328
329 -- ---------------------------------------------------------------------------
330 -- Check that the current value of the 'status' register
331 -- equals the given 'expected' value as a plain SLV casted to integer.
332 procedure check_counter_status_equal(
333 signal net : inout network_t;
334 expected : in integer;
335 base_address : in addr_t := (others => '0');
336 bus_handle : in bus_master_t := regs_bus_master;
337 message : in string := ""
338 ) is
339 constant register_array_message : string := "";
340 function base_address_message return string is
341 begin
342 if base_address /= 0 then
343 return " (at base address " & hex_image(std_logic_vector(base_address)) & ")";
344 end if;
345
346 return "";
347 end function;
348 constant base_message : string := (
349 "Checking the 'status' register"
350 & register_array_message
351 & base_address_message
352 & "."
353 );
354 function get_message return string is
355 begin
356 if message = "" then
357 return base_message;
358 end if;
359
360 return base_message & " " & message & ".";
361 end function;
362
363 variable got : integer;
364 begin
365 read_counter_status(
366 net => net,
367 value => got,
368 base_address => base_address,
369 bus_handle => bus_handle
370 );
371
372 check_equal(got=>got, expected=>expected, msg=>get_message);
373 end procedure;
374
375 -- Check that the current value of the 'status' register
376 -- equals the given 'expected' value.
377 procedure check_counter_status_equal(
378 signal net : inout network_t;
379 expected : in counter_status_t;
380 base_address : in addr_t := (others => '0');
381 bus_handle : in bus_master_t := regs_bus_master;
382 message : in string := ""
383 ) is
384 constant register_array_message : string := "";
385 function base_address_message return string is
386 begin
387 if base_address /= 0 then
388 return " (at base address " & hex_image(std_logic_vector(base_address)) & ")";
389 end if;
390
391 return "";
392 end function;
393 constant base_message : string := (
394 "Checking the 'status' register"
395 & register_array_message
396 & base_address_message
397 & "."
398 );
399 function get_message return string is
400 begin
401 if message = "" then
402 return base_message;
403 end if;
404
405 return base_message & " " & message & ".";
406 end function;
407
408 variable got : counter_status_t;
409 begin
410 read_counter_status(
411 net => net,
412 value => got,
413 base_address => base_address,
414 bus_handle => bus_handle
415 );
416
417 if got /= expected then
418 failing_check(
419 checker => default_checker,
420 msg => p_std_msg(
421 check_result => "Equality check failed",
422 msg => get_message,
423 ctx => (
424 "Got " & to_string(to_slv(got)) & ". Expected " & to_string(to_slv(expected)) & "."
425 )
426 )
427 );
428 end if;
429 end procedure;
430
431 -- Check that the current value of the 'enabled' field in the 'status' register
432 -- equals the given 'expected' value.
433 procedure check_counter_status_enabled_equal(
434 signal net : inout network_t;
435 expected : in std_ulogic;
436 base_address : in addr_t := (others => '0');
437 bus_handle : in bus_master_t := regs_bus_master;
438 message : in string := ""
439 ) is
440 constant register_array_message : string := "";
441 function base_address_message return string is
442 begin
443 if base_address /= 0 then
444 return " (at base address " & hex_image(std_logic_vector(base_address)) & ")";
445 end if;
446
447 return "";
448 end function;
449 constant base_message : string := (
450 "Checking the 'enabled' field in the 'status' register"
451 & register_array_message
452 & base_address_message
453 & "."
454 );
455 function get_message return string is
456 begin
457 if message = "" then
458 return base_message;
459 end if;
460
461 return base_message & " " & message & ".";
462 end function;
463
464 variable got_reg : counter_status_t := counter_status_init;
465 variable got : std_ulogic := counter_status_enabled_init;
466 begin
467 read_counter_status(
468 net => net,
469 value => got_reg,
470 base_address => base_address,
471 bus_handle => bus_handle
472 );
473 got := got_reg.enabled;
474
475 check_equal(got=>got, expected=>expected, msg=>get_message);
476 end procedure;
477
478 -- Check that the current value of the 'pulse_count' field in the 'status' register
479 -- equals the given 'expected' value.
480 procedure check_counter_status_pulse_count_equal(
481 signal net : inout network_t;
482 expected : in counter_status_pulse_count_t;
483 base_address : in addr_t := (others => '0');
484 bus_handle : in bus_master_t := regs_bus_master;
485 message : in string := ""
486 ) is
487 constant register_array_message : string := "";
488 function base_address_message return string is
489 begin
490 if base_address /= 0 then
491 return " (at base address " & hex_image(std_logic_vector(base_address)) & ")";
492 end if;
493
494 return "";
495 end function;
496 constant base_message : string := (
497 "Checking the 'pulse_count' field in the 'status' register"
498 & register_array_message
499 & base_address_message
500 & "."
501 );
502 function get_message return string is
503 begin
504 if message = "" then
505 return base_message;
506 end if;
507
508 return base_message & " " & message & ".";
509 end function;
510
511 variable got_reg : counter_status_t := counter_status_init;
512 variable got : counter_status_pulse_count_t := counter_status_pulse_count_init;
513 begin
514 read_counter_status(
515 net => net,
516 value => got_reg,
517 base_address => base_address,
518 bus_handle => bus_handle
519 );
520 got := got_reg.pulse_count;
521
522 check_equal(got=>got, expected=>expected, msg=>get_message);
523 end procedure;
524 -- ---------------------------------------------------------------------------
525
526end 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-- This file is automatically generated by hdl-registers version 6.1.1-dev.
2-- Code generator VhdlSimulationWaitUntilPackageGenerator version 1.0.0.
3-- Generated 2024-12-01 20:51 from file regs_counter.toml at commit 2ca830a4377d1e32.
4-- Register hash 49f02a8daa9dd4bc3dadeb2a1cfd61dcc38c3864.
5
6library ieee;
7use ieee.fixed_pkg.all;
8use ieee.std_logic_1164.all;
9use ieee.numeric_std.all;
10
11library vunit_lib;
12use vunit_lib.bus_master_pkg.bus_master_t;
13use vunit_lib.bus_master_pkg.wait_until_read_equals;
14use vunit_lib.com_types_pkg.max_timeout;
15use vunit_lib.com_types_pkg.network_t;
16use vunit_lib.string_ops.hex_image;
17
18library common;
19use common.addr_pkg.addr_t;
20use common.addr_pkg.addr_width;
21
22library reg_file;
23use reg_file.reg_file_pkg.reg_t;
24use reg_file.reg_operations_pkg.regs_bus_master;
25
26use work.counter_regs_pkg.all;
27use work.counter_register_record_pkg.all;
28
29
30package counter_register_wait_until_pkg is
31
32 -- ---------------------------------------------------------------------------
33 -- Wait until the 'config' register equals the given 'value'.
34 procedure wait_until_counter_config_equals(
35 signal net : inout network_t;
36 value : in counter_config_t;
37 base_address : in addr_t := (others => '0');
38 bus_handle : in bus_master_t := regs_bus_master;
39 timeout : delay_length := max_timeout;
40 message : string := ""
41 );
42
43 -- Wait until the 'condition' field in the 'config' register equals the given 'value'.
44 procedure wait_until_counter_config_condition_equals(
45 signal net : inout network_t;
46 value : in counter_config_condition_t;
47 base_address : in addr_t := (others => '0');
48 bus_handle : in bus_master_t := regs_bus_master;
49 timeout : delay_length := max_timeout;
50 message : string := ""
51 );
52
53 -- Wait until the 'increment' field in the 'config' register equals the given 'value'.
54 procedure wait_until_counter_config_increment_equals(
55 signal net : inout network_t;
56 value : in counter_config_increment_t;
57 base_address : in addr_t := (others => '0');
58 bus_handle : in bus_master_t := regs_bus_master;
59 timeout : delay_length := max_timeout;
60 message : string := ""
61 );
62 -- ---------------------------------------------------------------------------
63
64 -- ---------------------------------------------------------------------------
65 -- Wait until the 'status' register equals the given 'value'.
66 procedure wait_until_counter_status_equals(
67 signal net : inout network_t;
68 value : in counter_status_t;
69 base_address : in addr_t := (others => '0');
70 bus_handle : in bus_master_t := regs_bus_master;
71 timeout : delay_length := max_timeout;
72 message : string := ""
73 );
74
75 -- Wait until the 'enabled' field in the 'status' register equals the given 'value'.
76 procedure wait_until_counter_status_enabled_equals(
77 signal net : inout network_t;
78 value : in std_ulogic;
79 base_address : in addr_t := (others => '0');
80 bus_handle : in bus_master_t := regs_bus_master;
81 timeout : delay_length := max_timeout;
82 message : string := ""
83 );
84
85 -- Wait until the 'pulse_count' field in the 'status' register equals the given 'value'.
86 procedure wait_until_counter_status_pulse_count_equals(
87 signal net : inout network_t;
88 value : in counter_status_pulse_count_t;
89 base_address : in addr_t := (others => '0');
90 bus_handle : in bus_master_t := regs_bus_master;
91 timeout : delay_length := max_timeout;
92 message : string := ""
93 );
94 -- ---------------------------------------------------------------------------
95
96end package;
97
98package body counter_register_wait_until_pkg is
99
100 -- ---------------------------------------------------------------------------
101 -- Wait until the 'config' register equals the given 'value'.
102 procedure wait_until_counter_config_equals(
103 signal net : inout network_t;
104 value : in counter_config_t;
105 base_address : in addr_t := (others => '0');
106 bus_handle : in bus_master_t := regs_bus_master;
107 timeout : delay_length := max_timeout;
108 message : string := ""
109 ) is
110 constant reg_value : reg_t := to_slv(value);
111
112 constant reg_index : counter_reg_range := counter_config;
113 constant reg_address : addr_t := base_address + to_unsigned(4 * reg_index, addr_width);
114
115 constant register_array_message : string := "";
116 function base_address_message return string is
117 begin
118 if base_address /= 0 then
119 return " (at base address " & hex_image(std_logic_vector(base_address)) & ")";
120 end if;
121
122 return "";
123 end function;
124 constant base_message : string := (
125 "Timeout while waiting for the 'config' register"
126 & register_array_message
127 & base_address_message
128 & " to equal the given value: "
129 & to_string(reg_value)
130 & "."
131 );
132 function get_message return string is
133 begin
134 if message = "" then
135 return base_message;
136 end if;
137
138 return base_message & " " & message & ".";
139 end function;
140 begin
141 wait_until_read_equals(
142 net => net,
143 bus_handle => bus_handle,
144 addr => std_ulogic_vector(reg_address),
145 value => reg_value,
146 timeout => timeout,
147 msg => get_message
148 );
149 end procedure;
150
151 -- Wait until the 'condition' field in the 'config' register equals the given 'value'.
152 procedure wait_until_counter_config_condition_equals(
153 signal net : inout network_t;
154 value : in counter_config_condition_t;
155 base_address : in addr_t := (others => '0');
156 bus_handle : in bus_master_t := regs_bus_master;
157 timeout : delay_length := max_timeout;
158 message : string := ""
159 ) is
160 constant reg_value : reg_t := (
161 counter_config_condition => to_slv(value),
162 others => '-'
163 );
164
165 constant reg_index : counter_reg_range := counter_config;
166 constant reg_address : addr_t := base_address + to_unsigned(4 * reg_index, addr_width);
167
168 constant register_array_message : string := "";
169 function base_address_message return string is
170 begin
171 if base_address /= 0 then
172 return " (at base address " & hex_image(std_logic_vector(base_address)) & ")";
173 end if;
174
175 return "";
176 end function;
177 constant base_message : string := (
178 "Timeout while waiting for the 'condition' field in the 'config' register"
179 & register_array_message
180 & base_address_message
181 & " to equal the given value: "
182 & to_string(reg_value)
183 & "."
184 );
185 function get_message return string is
186 begin
187 if message = "" then
188 return base_message;
189 end if;
190
191 return base_message & " " & message & ".";
192 end function;
193 begin
194 wait_until_read_equals(
195 net => net,
196 bus_handle => bus_handle,
197 addr => std_ulogic_vector(reg_address),
198 value => reg_value,
199 timeout => timeout,
200 msg => get_message
201 );
202 end procedure;
203
204 -- Wait until the 'increment' field in the 'config' register equals the given 'value'.
205 procedure wait_until_counter_config_increment_equals(
206 signal net : inout network_t;
207 value : in counter_config_increment_t;
208 base_address : in addr_t := (others => '0');
209 bus_handle : in bus_master_t := regs_bus_master;
210 timeout : delay_length := max_timeout;
211 message : string := ""
212 ) is
213 constant reg_value : reg_t := (
214 counter_config_increment => to_counter_config_increment_slv(value),
215 others => '-'
216 );
217
218 constant reg_index : counter_reg_range := counter_config;
219 constant reg_address : addr_t := base_address + to_unsigned(4 * reg_index, addr_width);
220
221 constant register_array_message : string := "";
222 function base_address_message return string is
223 begin
224 if base_address /= 0 then
225 return " (at base address " & hex_image(std_logic_vector(base_address)) & ")";
226 end if;
227
228 return "";
229 end function;
230 constant base_message : string := (
231 "Timeout while waiting for the 'increment' field in the 'config' register"
232 & register_array_message
233 & base_address_message
234 & " to equal the given value: "
235 & to_string(reg_value)
236 & "."
237 );
238 function get_message return string is
239 begin
240 if message = "" then
241 return base_message;
242 end if;
243
244 return base_message & " " & message & ".";
245 end function;
246 begin
247 wait_until_read_equals(
248 net => net,
249 bus_handle => bus_handle,
250 addr => std_ulogic_vector(reg_address),
251 value => reg_value,
252 timeout => timeout,
253 msg => get_message
254 );
255 end procedure;
256 -- ---------------------------------------------------------------------------
257
258 -- ---------------------------------------------------------------------------
259 -- Wait until the 'status' register equals the given 'value'.
260 procedure wait_until_counter_status_equals(
261 signal net : inout network_t;
262 value : in counter_status_t;
263 base_address : in addr_t := (others => '0');
264 bus_handle : in bus_master_t := regs_bus_master;
265 timeout : delay_length := max_timeout;
266 message : string := ""
267 ) is
268 constant reg_value : reg_t := to_slv(value);
269
270 constant reg_index : counter_reg_range := counter_status;
271 constant reg_address : addr_t := base_address + to_unsigned(4 * reg_index, addr_width);
272
273 constant register_array_message : string := "";
274 function base_address_message return string is
275 begin
276 if base_address /= 0 then
277 return " (at base address " & hex_image(std_logic_vector(base_address)) & ")";
278 end if;
279
280 return "";
281 end function;
282 constant base_message : string := (
283 "Timeout while waiting for the 'status' register"
284 & register_array_message
285 & base_address_message
286 & " to equal the given value: "
287 & to_string(reg_value)
288 & "."
289 );
290 function get_message return string is
291 begin
292 if message = "" then
293 return base_message;
294 end if;
295
296 return base_message & " " & message & ".";
297 end function;
298 begin
299 wait_until_read_equals(
300 net => net,
301 bus_handle => bus_handle,
302 addr => std_ulogic_vector(reg_address),
303 value => reg_value,
304 timeout => timeout,
305 msg => get_message
306 );
307 end procedure;
308
309 -- Wait until the 'enabled' field in the 'status' register equals the given 'value'.
310 procedure wait_until_counter_status_enabled_equals(
311 signal net : inout network_t;
312 value : in std_ulogic;
313 base_address : in addr_t := (others => '0');
314 bus_handle : in bus_master_t := regs_bus_master;
315 timeout : delay_length := max_timeout;
316 message : string := ""
317 ) is
318 constant reg_value : reg_t := (
319 counter_status_enabled => value,
320 others => '-'
321 );
322
323 constant reg_index : counter_reg_range := counter_status;
324 constant reg_address : addr_t := base_address + to_unsigned(4 * reg_index, addr_width);
325
326 constant register_array_message : string := "";
327 function base_address_message return string is
328 begin
329 if base_address /= 0 then
330 return " (at base address " & hex_image(std_logic_vector(base_address)) & ")";
331 end if;
332
333 return "";
334 end function;
335 constant base_message : string := (
336 "Timeout while waiting for the 'enabled' field in the 'status' register"
337 & register_array_message
338 & base_address_message
339 & " to equal the given value: "
340 & to_string(reg_value)
341 & "."
342 );
343 function get_message return string is
344 begin
345 if message = "" then
346 return base_message;
347 end if;
348
349 return base_message & " " & message & ".";
350 end function;
351 begin
352 wait_until_read_equals(
353 net => net,
354 bus_handle => bus_handle,
355 addr => std_ulogic_vector(reg_address),
356 value => reg_value,
357 timeout => timeout,
358 msg => get_message
359 );
360 end procedure;
361
362 -- Wait until the 'pulse_count' field in the 'status' register equals the given 'value'.
363 procedure wait_until_counter_status_pulse_count_equals(
364 signal net : inout network_t;
365 value : in counter_status_pulse_count_t;
366 base_address : in addr_t := (others => '0');
367 bus_handle : in bus_master_t := regs_bus_master;
368 timeout : delay_length := max_timeout;
369 message : string := ""
370 ) is
371 constant reg_value : reg_t := (
372 counter_status_pulse_count => to_counter_status_pulse_count_slv(value),
373 others => '-'
374 );
375
376 constant reg_index : counter_reg_range := counter_status;
377 constant reg_address : addr_t := base_address + to_unsigned(4 * reg_index, addr_width);
378
379 constant register_array_message : string := "";
380 function base_address_message return string is
381 begin
382 if base_address /= 0 then
383 return " (at base address " & hex_image(std_logic_vector(base_address)) & ")";
384 end if;
385
386 return "";
387 end function;
388 constant base_message : string := (
389 "Timeout while waiting for the 'pulse_count' field in the 'status' register"
390 & register_array_message
391 & base_address_message
392 & " to equal the given value: "
393 & to_string(reg_value)
394 & "."
395 );
396 function get_message return string is
397 begin
398 if message = "" then
399 return base_message;
400 end if;
401
402 return base_message & " " & message & ".";
403 end function;
404 begin
405 wait_until_read_equals(
406 net => net,
407 bus_handle => bus_handle,
408 addr => std_ulogic_vector(reg_address),
409 value => reg_value,
410 timeout => timeout,
411 msg => get_message
412 );
413 end procedure;
414 -- ---------------------------------------------------------------------------
415
416end 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 reg_file_pkg.vhd.
Can be downloaded from GitHub here:
https://github.com/hdl-modules/hdl-modules/blob/main/modules/reg_file/src/reg_file_pkg.vhd
The VhdlSimulationReadWritePackageGenerator
and
VhdlSimulationWaitUntilPackageGenerator
packages
furthermore depend on reg_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 reg_file library, axi library and axi_lite library for more details.