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 a VHDL package with register indexes, 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.VhdlSimulationPackageGenerator
generates a VHDL package with procedures for reading/writing register values.VhdlAxiLiteWrapperGenerator
generates a VHDL entity that wraps an AXI-Lite general register file, and exposes register values to application using the natively typed records.
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[register.config]
3
4mode = "r_w"
5
6enumeration.mode.description = "Set mode for how the counter operates."
7enumeration.mode.element.clock_cycles = "Increment counter each clock cycle."
8enumeration.mode.element.clock_cycles_with_enable = """
9Increment counter each clock cycle when **clock_enable** is asserted.
10"""
11enumeration.mode.element.enable_edges = """
12Increment counter each time **clock_enable** changes state.
13"""
14
15integer.increment.description = "How much to increment counter."
16integer.increment.max_value = 15
17
18
19################################################################################
20[register.command]
21
22mode = "wpulse"
23
24bit.start.description = "Write '1' to start operation."
25
26bit.stop.description = "Write '1' to stop operation."
27
28
29################################################################################
30[register.status]
31
32mode = "r"
33
34bit.enabled.description = "Reads as '1' if operation is enabled."
35
36integer.pulse_count.max_value = 255
37integer.pulse_count.description = """
38Number of pulses that have been sent.
39Will wrap around.
40Value will be cleared to zero when **config** register is written.
41"""
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_package import VhdlSimulationPackageGenerator
10from hdl_registers.parser.toml import from_toml
11
12THIS_DIR = Path(__file__).parent
13
14
15def main(output_folder: Path):
16 """
17 Create register VHDL artifacts from the "counter" example module.
18 """
19 register_list = from_toml(
20 name="counter", toml_file=THIS_DIR.parent / "sim" / "regs_counter.toml"
21 )
22
23 VhdlRegisterPackageGenerator(
24 register_list=register_list, output_folder=output_folder
25 ).create_if_needed()
26
27 VhdlRecordPackageGenerator(
28 register_list=register_list, output_folder=output_folder
29 ).create_if_needed()
30
31 VhdlSimulationPackageGenerator(
32 register_list=register_list, output_folder=output_folder
33 ).create_if_needed()
34
35 VhdlAxiLiteWrapperGenerator(
36 register_list=register_list, output_folder=output_folder
37 ).create_if_needed()
38
39
40if __name__ == "__main__":
41 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.
mode_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;
9use axi.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.mode is
97 when mode_clock_cycles =>
98 count <= count + regs_down.config.increment;
99
100 when mode_clock_cycles_with_enable =>
101 if clock_enable then
102 count <= count + regs_down.config.increment;
103 end if;
104
105 when mode_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 VHDL example counter implementation above.
The testbench uses register read/write procedures from the package produced by
VhdlSimulationPackageGenerator
, which can be seen below. For examplewrite_counter_config
.The
wait_until_counter_status_pulse_count_equals
call 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 instantiates axi_lite_master.vhd which creates AXI-Lite transactions based on the VUnit bus master verification component interface commands created by the generated simulation package.
Click to expand/collapse code.
1library ieee;
2use ieee.std_logic_1164.all;
3
4library vunit_lib;
5context vunit_lib.vc_context;
6context vunit_lib.vunit_context;
7
8library axi;
9use axi.axi_lite_pkg.all;
10
11library bfm;
12
13library reg_file;
14use reg_file.reg_operations_pkg.all;
15
16use work.counter_regs_pkg.all;
17use work.counter_register_record_pkg.all;
18use work.counter_register_simulation_pkg.all;
19
20
21entity tb_counter is
22 generic (
23 runner_cfg : string
24 );
25end entity;
26
27architecture tb of tb_counter is
28
29 signal clk : std_ulogic := '0';
30
31 signal regs_m2s : axi_lite_m2s_t := axi_lite_m2s_init;
32 signal regs_s2m : axi_lite_s2m_t := axi_lite_s2m_init;
33
34 signal pulse, clock_enable : std_ulogic := '0';
35
36begin
37
38 clk <= not clk after 5 ns;
39 test_runner_watchdog(runner, 1 ms);
40
41
42 ------------------------------------------------------------------------------
43 main : process
44 variable config : counter_config_t := counter_config_init;
45 variable status : counter_status_t := counter_status_init;
46 begin
47 test_runner_setup(runner, runner_cfg);
48
49 -- Check initial state.
50 read_counter_status(net=>net, value=>status);
51 check_equal(status.enabled, '0');
52 check_equal(status.pulse_count, 0);
53
54 if run("test_count_clock_cycles") then
55 config.mode := mode_clock_cycles;
56 config.increment := 13;
57
58 elsif run("test_count_clock_cycles_with_enable") then
59 config.mode := mode_clock_cycles_with_enable;
60 config.increment := 8;
61
62 clock_enable <= '1';
63 end if;
64
65 -- Set configuration, which depends on test case.
66 write_counter_config(net=>net, value=>config);
67
68 -- Enable the operation.
69 write_counter_command_start(net=>net, value=>'1');
70
71 -- Check updated status.
72 read_counter_status(net=>net, value=>status);
73 check_equal(status.enabled, '1');
74 check_equal(status.pulse_count, 0);
75
76 -- Wait until a number of pulses have passed.
77 wait_until_counter_status_pulse_count_equals(net=>net, value=>10);
78
79 test_runner_cleanup(runner);
80 end process;
81
82
83 ------------------------------------------------------------------------------
84 axi_lite_master_inst : entity bfm.axi_lite_master
85 port map (
86 clk => clk,
87 --
88 axi_lite_m2s => regs_m2s,
89 axi_lite_s2m => regs_s2m
90 );
91
92
93 ------------------------------------------------------------------------------
94 counter_inst : entity work.counter
95 port map (
96 clk => clk,
97 --
98 regs_m2s => regs_m2s,
99 regs_s2m => regs_s2m,
100 --
101 clock_enable => clock_enable,
102 pulse => pulse
103 );
104
105end architecture;
Generated VHDL register package
Below is the generated register package, created from the TOML file above via the
VhdlRegisterPackageGenerator
class.
Click to expand/collapse code.
1-- This file is automatically generated by hdl-registers version 4.1.1-dev2.
2-- Code generator VhdlRegisterPackageGenerator version 1.0.0.
3-- Generated 2023-12-04 10:43 from file regs_counter.toml at commit d6ece437d0e3b2bc.
4-- Register hash 79eb071caf7e3f78ee67fa5265f7ef0edb0ea269.
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 'mode' field.
44 subtype counter_config_mode is natural range 1 downto 0;
45 -- Width of the 'mode' field.
46 constant counter_config_mode_width : positive := 2;
47 -- Type for the 'mode' field.
48 type counter_config_mode_t is (
49 mode_clock_cycles,
50 mode_clock_cycles_with_enable,
51 mode_enable_edges
52 );
53 -- Default value of the 'mode' field.
54 constant counter_config_mode_init : counter_config_mode_t := mode_clock_cycles;
55 -- Type for the 'mode' field as an SLV.
56 subtype counter_config_mode_slv_t is std_ulogic_vector(1 downto 0);
57 -- Cast a 'mode' field value to SLV.
58 function to_slv(data : counter_config_mode_t) return counter_config_mode_slv_t;
59 -- Get a 'mode' field value from a register value.
60 function to_counter_config_mode(data : reg_t) return counter_config_mode_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 function to_slv(data : counter_config_mode_t) return counter_config_mode_slv_t is
128 constant data_int : natural := counter_config_mode_t'pos(data);
129 constant result : counter_config_mode_slv_t := std_ulogic_vector(
130 to_unsigned(data_int, counter_config_mode_width)
131 );
132 begin
133 return result;
134 end function;
135
136 function to_counter_config_mode(data : reg_t) return counter_config_mode_t is
137 constant field_slv : counter_config_mode_slv_t := data(counter_config_mode);
138 constant field_int : natural := to_integer(unsigned(field_slv));
139 constant result : counter_config_mode_t := counter_config_mode_t'val(field_int);
140 begin
141 return result;
142 end function;
143
144 function to_counter_config_increment_slv(data : counter_config_increment_t) return counter_config_increment_slv_t is
145 constant result : counter_config_increment_slv_t := std_ulogic_vector(to_unsigned(data, counter_config_increment_width));
146 begin
147 return result;
148 end function;
149
150 function to_counter_config_increment(data : reg_t) return counter_config_increment_t is
151 constant result : integer := to_integer(unsigned(data(counter_config_increment)));
152 begin
153 return result;
154 end function;
155
156 function to_counter_status_pulse_count_slv(data : counter_status_pulse_count_t) return counter_status_pulse_count_slv_t is
157 constant result : counter_status_pulse_count_slv_t := std_ulogic_vector(to_unsigned(data, counter_status_pulse_count_width));
158 begin
159 return result;
160 end function;
161
162 function to_counter_status_pulse_count(data : reg_t) return counter_status_pulse_count_t is
163 constant result : integer := to_integer(unsigned(data(counter_status_pulse_count)));
164 begin
165 return result;
166 end function;
167
168end package body;
Generated VHDL record package
Below is the generated register package, created from the TOML file above via the
VhdlRecordPackageGenerator
class.
Click to expand/collapse code.
1-- This file is automatically generated by hdl-registers version 4.1.1-dev2.
2-- Code generator VhdlRecordPackageGenerator version 1.0.0.
3-- Generated 2023-12-04 10:43 from file regs_counter.toml at commit d6ece437d0e3b2bc.
4-- Register hash 79eb071caf7e3f78ee67fa5265f7ef0edb0ea269.
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
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 mode : counter_config_mode_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 mode => counter_config_mode_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_mode) := to_slv(data.mode);
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.mode := to_counter_config_mode(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 simulation package
Below is the generated register simulation package, created from the TOML file above via the
VhdlSimulationPackageGenerator
class.
Click to expand/collapse code.
1-- This file is automatically generated by hdl-registers version 4.1.1-dev2.
2-- Code generator VhdlSimulationPackageGenerator version 1.0.0.
3-- Generated 2023-12-04 10:43 from file regs_counter.toml at commit d6ece437d0e3b2bc.
4-- Register hash 79eb071caf7e3f78ee67fa5265f7ef0edb0ea269.
5
6library ieee;
7use ieee.std_logic_1164.all;
8use ieee.numeric_std.all;
9
10library vunit_lib;
11context vunit_lib.vc_context;
12
13library common;
14use common.addr_pkg.all;
15
16library reg_file;
17use reg_file.reg_file_pkg.all;
18use reg_file.reg_operations_pkg.all;
19
20use work.counter_regs_pkg.all;
21use work.counter_register_record_pkg.all;
22
23
24package counter_register_simulation_pkg is
25
26 -- ---------------------------------------------------------------------------
27 -- Read the 'config' register.
28 procedure read_counter_config(
29 signal net : inout network_t;
30 value : out counter_config_t;
31 base_address : in addr_t := (others => '0');
32 bus_handle : in bus_master_t := regs_bus_master
33 );
34
35 -- Wait until the 'config' register equals the given 'value'.
36 procedure wait_until_counter_config_equals(
37 signal net : inout network_t;
38 value : in counter_config_t;
39 base_address : in addr_t := (others => '0');
40 bus_handle : in bus_master_t := regs_bus_master;
41 timeout : delay_length := max_timeout;
42 message : string := ""
43 );
44
45 -- Read the 'mode' field within the 'config' register.
46 procedure read_counter_config_mode(
47 signal net : inout network_t;
48 value : out counter_config_mode_t;
49 base_address : in addr_t := (others => '0');
50 bus_handle : in bus_master_t := regs_bus_master
51 );
52
53 -- Wait until the 'mode' field within the 'config' register equals the given 'value'.
54 procedure wait_until_counter_config_mode_equals(
55 signal net : inout network_t;
56 value : in counter_config_mode_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 -- Read the 'increment' field within the 'config' register.
64 procedure read_counter_config_increment(
65 signal net : inout network_t;
66 value : out counter_config_increment_t;
67 base_address : in addr_t := (others => '0');
68 bus_handle : in bus_master_t := regs_bus_master
69 );
70
71 -- Wait until the 'increment' field within the 'config' register equals the given 'value'.
72 procedure wait_until_counter_config_increment_equals(
73 signal net : inout network_t;
74 value : in counter_config_increment_t;
75 base_address : in addr_t := (others => '0');
76 bus_handle : in bus_master_t := regs_bus_master;
77 timeout : delay_length := max_timeout;
78 message : string := ""
79 );
80
81 -- Write the 'config' register.
82 procedure write_counter_config(
83 signal net : inout network_t;
84 value : in counter_config_t;
85 base_address : in addr_t := (others => '0');
86 bus_handle : in bus_master_t := regs_bus_master
87 );
88
89 -- Write the 'mode' field within the 'config' register.
90 -- Will read-modify-write the register to set the field to the supplied 'value'.
91 procedure write_counter_config_mode(
92 signal net : inout network_t;
93 value : in counter_config_mode_t;
94 base_address : in addr_t := (others => '0');
95 bus_handle : in bus_master_t := regs_bus_master
96 );
97
98 -- Write the 'increment' field within the 'config' register.
99 -- Will read-modify-write the register to set the field to the supplied 'value'.
100 procedure write_counter_config_increment(
101 signal net : inout network_t;
102 value : in counter_config_increment_t;
103 base_address : in addr_t := (others => '0');
104 bus_handle : in bus_master_t := regs_bus_master
105 );
106 -- ---------------------------------------------------------------------------
107
108 -- ---------------------------------------------------------------------------
109 -- Write the 'command' register.
110 procedure write_counter_command(
111 signal net : inout network_t;
112 value : in counter_command_t;
113 base_address : in addr_t := (others => '0');
114 bus_handle : in bus_master_t := regs_bus_master
115 );
116
117 -- Write the 'start' field within the 'command' register.
118 -- Will write the whole register, with the field set to the
119 -- supplied 'value' and all other fields to their default values.
120 procedure write_counter_command_start(
121 signal net : inout network_t;
122 value : in std_ulogic;
123 base_address : in addr_t := (others => '0');
124 bus_handle : in bus_master_t := regs_bus_master
125 );
126
127 -- Write the 'stop' field within the 'command' register.
128 -- Will write the whole register, with the field set to the
129 -- supplied 'value' and all other fields to their default values.
130 procedure write_counter_command_stop(
131 signal net : inout network_t;
132 value : in std_ulogic;
133 base_address : in addr_t := (others => '0');
134 bus_handle : in bus_master_t := regs_bus_master
135 );
136 -- ---------------------------------------------------------------------------
137
138 -- ---------------------------------------------------------------------------
139 -- Read the 'status' register.
140 procedure read_counter_status(
141 signal net : inout network_t;
142 value : out counter_status_t;
143 base_address : in addr_t := (others => '0');
144 bus_handle : in bus_master_t := regs_bus_master
145 );
146
147 -- Wait until the 'status' register equals the given 'value'.
148 procedure wait_until_counter_status_equals(
149 signal net : inout network_t;
150 value : in counter_status_t;
151 base_address : in addr_t := (others => '0');
152 bus_handle : in bus_master_t := regs_bus_master;
153 timeout : delay_length := max_timeout;
154 message : string := ""
155 );
156
157 -- Read the 'enabled' field within the 'status' register.
158 procedure read_counter_status_enabled(
159 signal net : inout network_t;
160 value : out std_ulogic;
161 base_address : in addr_t := (others => '0');
162 bus_handle : in bus_master_t := regs_bus_master
163 );
164
165 -- Wait until the 'enabled' field within the 'status' register equals the given 'value'.
166 procedure wait_until_counter_status_enabled_equals(
167 signal net : inout network_t;
168 value : in std_ulogic;
169 base_address : in addr_t := (others => '0');
170 bus_handle : in bus_master_t := regs_bus_master;
171 timeout : delay_length := max_timeout;
172 message : string := ""
173 );
174
175 -- Read the 'pulse_count' field within the 'status' register.
176 procedure read_counter_status_pulse_count(
177 signal net : inout network_t;
178 value : out counter_status_pulse_count_t;
179 base_address : in addr_t := (others => '0');
180 bus_handle : in bus_master_t := regs_bus_master
181 );
182
183 -- Wait until the 'pulse_count' field within the 'status' register equals the given 'value'.
184 procedure wait_until_counter_status_pulse_count_equals(
185 signal net : inout network_t;
186 value : in counter_status_pulse_count_t;
187 base_address : in addr_t := (others => '0');
188 bus_handle : in bus_master_t := regs_bus_master;
189 timeout : delay_length := max_timeout;
190 message : string := ""
191 );
192 -- ---------------------------------------------------------------------------
193
194end package;
195
196package body counter_register_simulation_pkg is
197
198 -- ---------------------------------------------------------------------------
199 -- Read the 'config' register.
200 procedure read_counter_config(
201 signal net : inout network_t;
202 value : out counter_config_t;
203 base_address : in addr_t := (others => '0');
204 bus_handle : in bus_master_t := regs_bus_master
205 ) is
206 constant reg_index : counter_reg_range := counter_config;
207 variable reg_value : reg_t := (others => '0');
208 begin
209 read_reg(
210 net => net,
211 reg_index => reg_index,
212 value => reg_value,
213 base_address => base_address,
214 bus_handle => bus_handle
215 );
216 value := to_counter_config(reg_value);
217 end procedure;
218
219 -- Wait until the 'config' register equals the given 'value'.
220 procedure wait_until_counter_config_equals(
221 signal net : inout network_t;
222 value : in counter_config_t;
223 base_address : in addr_t := (others => '0');
224 bus_handle : in bus_master_t := regs_bus_master;
225 timeout : delay_length := max_timeout;
226 message : string := ""
227 ) is
228 constant reg_value : reg_t := to_slv(value);
229 constant reg_index : counter_reg_range := counter_config;
230 constant address : addr_t := base_address or to_unsigned(4 * reg_index, addr_t'length);
231
232 constant base_timeout_message : string := (
233 "Timeout while waiting for the 'config' register to equal the given value."
234 & " value: " & to_string(reg_value)
235 & " - register index: " & to_string(reg_index)
236 & " - base address: " & to_string(base_address)
237 );
238 function get_timeout_message return string is
239 begin
240 if message = "" then
241 return base_timeout_message;
242 end if;
243
244 return base_timeout_message & " - message: " & message;
245 end function;
246 constant timeout_message : string := get_timeout_message;
247 begin
248 wait_until_read_equals(
249 net=>net,
250 bus_handle=>bus_handle,
251 addr=>std_ulogic_vector(address),
252 value=>reg_value,
253 timeout=>timeout,
254 msg=>timeout_message
255 );
256 end procedure;
257
258 -- Read the 'mode' field within the 'config' register.
259 procedure read_counter_config_mode(
260 signal net : inout network_t;
261 value : out counter_config_mode_t;
262 base_address : in addr_t := (others => '0');
263 bus_handle : in bus_master_t := regs_bus_master
264 ) is
265 variable reg_value : counter_config_t := counter_config_init;
266 begin
267 read_counter_config(
268 net => net,
269 value => reg_value,
270 base_address => base_address,
271 bus_handle => bus_handle
272 );
273 value := reg_value.mode;
274 end procedure;
275
276 -- Wait until the 'mode' field within the 'config' register equals the given 'value'.
277 procedure wait_until_counter_config_mode_equals(
278 signal net : inout network_t;
279 value : in counter_config_mode_t;
280 base_address : in addr_t := (others => '0');
281 bus_handle : in bus_master_t := regs_bus_master;
282 timeout : delay_length := max_timeout;
283 message : string := ""
284 ) is
285 constant reg_value : reg_t := (
286 counter_config_mode => to_slv(value),
287 others => '-'
288 );
289 constant reg_index : counter_reg_range := counter_config;
290 constant address : addr_t := base_address or to_unsigned(4 * reg_index, addr_t'length);
291
292 constant base_timeout_message : string := (
293 "Timeout while waiting for the 'config' register to equal the given value."
294 & " value: " & to_string(reg_value)
295 & " - register index: " & to_string(reg_index)
296 & " - base address: " & to_string(base_address)
297 );
298 function get_timeout_message return string is
299 begin
300 if message = "" then
301 return base_timeout_message;
302 end if;
303
304 return base_timeout_message & " - message: " & message;
305 end function;
306 constant timeout_message : string := get_timeout_message;
307 begin
308 wait_until_read_equals(
309 net=>net,
310 bus_handle=>bus_handle,
311 addr=>std_ulogic_vector(address),
312 value=>reg_value,
313 timeout=>timeout,
314 msg=>timeout_message
315 );
316 end procedure;
317
318 -- Read the 'increment' field within the 'config' register.
319 procedure read_counter_config_increment(
320 signal net : inout network_t;
321 value : out counter_config_increment_t;
322 base_address : in addr_t := (others => '0');
323 bus_handle : in bus_master_t := regs_bus_master
324 ) is
325 variable reg_value : counter_config_t := counter_config_init;
326 begin
327 read_counter_config(
328 net => net,
329 value => reg_value,
330 base_address => base_address,
331 bus_handle => bus_handle
332 );
333 value := reg_value.increment;
334 end procedure;
335
336 -- Wait until the 'increment' field within the 'config' register equals the given 'value'.
337 procedure wait_until_counter_config_increment_equals(
338 signal net : inout network_t;
339 value : in counter_config_increment_t;
340 base_address : in addr_t := (others => '0');
341 bus_handle : in bus_master_t := regs_bus_master;
342 timeout : delay_length := max_timeout;
343 message : string := ""
344 ) is
345 constant reg_value : reg_t := (
346 counter_config_increment => to_counter_config_increment_slv(value),
347 others => '-'
348 );
349 constant reg_index : counter_reg_range := counter_config;
350 constant address : addr_t := base_address or to_unsigned(4 * reg_index, addr_t'length);
351
352 constant base_timeout_message : string := (
353 "Timeout while waiting for the 'config' register to equal the given value."
354 & " value: " & to_string(reg_value)
355 & " - register index: " & to_string(reg_index)
356 & " - base address: " & to_string(base_address)
357 );
358 function get_timeout_message return string is
359 begin
360 if message = "" then
361 return base_timeout_message;
362 end if;
363
364 return base_timeout_message & " - message: " & message;
365 end function;
366 constant timeout_message : string := get_timeout_message;
367 begin
368 wait_until_read_equals(
369 net=>net,
370 bus_handle=>bus_handle,
371 addr=>std_ulogic_vector(address),
372 value=>reg_value,
373 timeout=>timeout,
374 msg=>timeout_message
375 );
376 end procedure;
377
378 -- Write the 'config' register.
379 procedure write_counter_config(
380 signal net : inout network_t;
381 value : in counter_config_t;
382 base_address : in addr_t := (others => '0');
383 bus_handle : in bus_master_t := regs_bus_master
384 ) is
385 constant reg_index : counter_reg_range := counter_config;
386 constant reg_value : reg_t := to_slv(value);
387 begin
388 write_reg(
389 net => net,
390 reg_index => reg_index,
391 value => reg_value,
392 base_address => base_address,
393 bus_handle => bus_handle
394 );
395 end procedure;
396
397 -- Write the 'mode' field within the 'config' register.
398 -- Will read-modify-write the register to set the field to the supplied 'value'.
399 procedure write_counter_config_mode(
400 signal net : inout network_t;
401 value : in counter_config_mode_t;
402 base_address : in addr_t := (others => '0');
403 bus_handle : in bus_master_t := regs_bus_master
404 ) is
405 variable reg_value : counter_config_t := counter_config_init;
406 begin
407 read_counter_config(
408 net => net,
409 value => reg_value,
410 base_address => base_address,
411 bus_handle => bus_handle
412 );
413 reg_value.mode := value;
414
415 write_counter_config(
416 net => net,
417 value => reg_value,
418 base_address => base_address,
419 bus_handle => bus_handle
420 );
421 end procedure;
422
423 -- Write the 'increment' field within the 'config' register.
424 -- Will read-modify-write the register to set the field to the supplied 'value'.
425 procedure write_counter_config_increment(
426 signal net : inout network_t;
427 value : in counter_config_increment_t;
428 base_address : in addr_t := (others => '0');
429 bus_handle : in bus_master_t := regs_bus_master
430 ) is
431 variable reg_value : counter_config_t := counter_config_init;
432 begin
433 read_counter_config(
434 net => net,
435 value => reg_value,
436 base_address => base_address,
437 bus_handle => bus_handle
438 );
439 reg_value.increment := value;
440
441 write_counter_config(
442 net => net,
443 value => reg_value,
444 base_address => base_address,
445 bus_handle => bus_handle
446 );
447 end procedure;
448 -- ---------------------------------------------------------------------------
449
450 -- ---------------------------------------------------------------------------
451 -- Write the 'command' register.
452 procedure write_counter_command(
453 signal net : inout network_t;
454 value : in counter_command_t;
455 base_address : in addr_t := (others => '0');
456 bus_handle : in bus_master_t := regs_bus_master
457 ) is
458 constant reg_index : counter_reg_range := counter_command;
459 constant reg_value : reg_t := to_slv(value);
460 begin
461 write_reg(
462 net => net,
463 reg_index => reg_index,
464 value => reg_value,
465 base_address => base_address,
466 bus_handle => bus_handle
467 );
468 end procedure;
469
470 -- Write the 'start' field within the 'command' register.
471 -- Will write the whole register, with the field set to the
472 -- supplied 'value' and all other fields to their default values.
473 procedure write_counter_command_start(
474 signal net : inout network_t;
475 value : in std_ulogic;
476 base_address : in addr_t := (others => '0');
477 bus_handle : in bus_master_t := regs_bus_master
478 ) is
479 variable reg_value : counter_command_t := counter_command_init;
480 begin
481 reg_value.start := value;
482
483 write_counter_command(
484 net => net,
485 value => reg_value,
486 base_address => base_address,
487 bus_handle => bus_handle
488 );
489 end procedure;
490
491 -- Write the 'stop' field within the 'command' register.
492 -- Will write the whole register, with the field set to the
493 -- supplied 'value' and all other fields to their default values.
494 procedure write_counter_command_stop(
495 signal net : inout network_t;
496 value : in std_ulogic;
497 base_address : in addr_t := (others => '0');
498 bus_handle : in bus_master_t := regs_bus_master
499 ) is
500 variable reg_value : counter_command_t := counter_command_init;
501 begin
502 reg_value.stop := value;
503
504 write_counter_command(
505 net => net,
506 value => reg_value,
507 base_address => base_address,
508 bus_handle => bus_handle
509 );
510 end procedure;
511 -- ---------------------------------------------------------------------------
512
513 -- ---------------------------------------------------------------------------
514 -- Read the 'status' register.
515 procedure read_counter_status(
516 signal net : inout network_t;
517 value : out counter_status_t;
518 base_address : in addr_t := (others => '0');
519 bus_handle : in bus_master_t := regs_bus_master
520 ) is
521 constant reg_index : counter_reg_range := counter_status;
522 variable reg_value : reg_t := (others => '0');
523 begin
524 read_reg(
525 net => net,
526 reg_index => reg_index,
527 value => reg_value,
528 base_address => base_address,
529 bus_handle => bus_handle
530 );
531 value := to_counter_status(reg_value);
532 end procedure;
533
534 -- Wait until the 'status' register equals the given 'value'.
535 procedure wait_until_counter_status_equals(
536 signal net : inout network_t;
537 value : in counter_status_t;
538 base_address : in addr_t := (others => '0');
539 bus_handle : in bus_master_t := regs_bus_master;
540 timeout : delay_length := max_timeout;
541 message : string := ""
542 ) is
543 constant reg_value : reg_t := to_slv(value);
544 constant reg_index : counter_reg_range := counter_status;
545 constant address : addr_t := base_address or to_unsigned(4 * reg_index, addr_t'length);
546
547 constant base_timeout_message : string := (
548 "Timeout while waiting for the 'status' register to equal the given value."
549 & " value: " & to_string(reg_value)
550 & " - register index: " & to_string(reg_index)
551 & " - base address: " & to_string(base_address)
552 );
553 function get_timeout_message return string is
554 begin
555 if message = "" then
556 return base_timeout_message;
557 end if;
558
559 return base_timeout_message & " - message: " & message;
560 end function;
561 constant timeout_message : string := get_timeout_message;
562 begin
563 wait_until_read_equals(
564 net=>net,
565 bus_handle=>bus_handle,
566 addr=>std_ulogic_vector(address),
567 value=>reg_value,
568 timeout=>timeout,
569 msg=>timeout_message
570 );
571 end procedure;
572
573 -- Read the 'enabled' field within the 'status' register.
574 procedure read_counter_status_enabled(
575 signal net : inout network_t;
576 value : out std_ulogic;
577 base_address : in addr_t := (others => '0');
578 bus_handle : in bus_master_t := regs_bus_master
579 ) is
580 variable reg_value : counter_status_t := counter_status_init;
581 begin
582 read_counter_status(
583 net => net,
584 value => reg_value,
585 base_address => base_address,
586 bus_handle => bus_handle
587 );
588 value := reg_value.enabled;
589 end procedure;
590
591 -- Wait until the 'enabled' field within the 'status' register equals the given 'value'.
592 procedure wait_until_counter_status_enabled_equals(
593 signal net : inout network_t;
594 value : in std_ulogic;
595 base_address : in addr_t := (others => '0');
596 bus_handle : in bus_master_t := regs_bus_master;
597 timeout : delay_length := max_timeout;
598 message : string := ""
599 ) is
600 constant reg_value : reg_t := (
601 counter_status_enabled => value,
602 others => '-'
603 );
604 constant reg_index : counter_reg_range := counter_status;
605 constant address : addr_t := base_address or to_unsigned(4 * reg_index, addr_t'length);
606
607 constant base_timeout_message : string := (
608 "Timeout while waiting for the 'status' register to equal the given value."
609 & " value: " & to_string(reg_value)
610 & " - register index: " & to_string(reg_index)
611 & " - base address: " & to_string(base_address)
612 );
613 function get_timeout_message return string is
614 begin
615 if message = "" then
616 return base_timeout_message;
617 end if;
618
619 return base_timeout_message & " - message: " & message;
620 end function;
621 constant timeout_message : string := get_timeout_message;
622 begin
623 wait_until_read_equals(
624 net=>net,
625 bus_handle=>bus_handle,
626 addr=>std_ulogic_vector(address),
627 value=>reg_value,
628 timeout=>timeout,
629 msg=>timeout_message
630 );
631 end procedure;
632
633 -- Read the 'pulse_count' field within the 'status' register.
634 procedure read_counter_status_pulse_count(
635 signal net : inout network_t;
636 value : out counter_status_pulse_count_t;
637 base_address : in addr_t := (others => '0');
638 bus_handle : in bus_master_t := regs_bus_master
639 ) is
640 variable reg_value : counter_status_t := counter_status_init;
641 begin
642 read_counter_status(
643 net => net,
644 value => reg_value,
645 base_address => base_address,
646 bus_handle => bus_handle
647 );
648 value := reg_value.pulse_count;
649 end procedure;
650
651 -- Wait until the 'pulse_count' field within the 'status' register equals the given 'value'.
652 procedure wait_until_counter_status_pulse_count_equals(
653 signal net : inout network_t;
654 value : in counter_status_pulse_count_t;
655 base_address : in addr_t := (others => '0');
656 bus_handle : in bus_master_t := regs_bus_master;
657 timeout : delay_length := max_timeout;
658 message : string := ""
659 ) is
660 constant reg_value : reg_t := (
661 counter_status_pulse_count => to_counter_status_pulse_count_slv(value),
662 others => '-'
663 );
664 constant reg_index : counter_reg_range := counter_status;
665 constant address : addr_t := base_address or to_unsigned(4 * reg_index, addr_t'length);
666
667 constant base_timeout_message : string := (
668 "Timeout while waiting for the 'status' register to equal the given value."
669 & " value: " & to_string(reg_value)
670 & " - register index: " & to_string(reg_index)
671 & " - base address: " & to_string(base_address)
672 );
673 function get_timeout_message return string is
674 begin
675 if message = "" then
676 return base_timeout_message;
677 end if;
678
679 return base_timeout_message & " - message: " & message;
680 end function;
681 constant timeout_message : string := get_timeout_message;
682 begin
683 wait_until_read_equals(
684 net=>net,
685 bus_handle=>bus_handle,
686 addr=>std_ulogic_vector(address),
687 value=>reg_value,
688 timeout=>timeout,
689 msg=>timeout_message
690 );
691 end procedure;
692 -- ---------------------------------------------------------------------------
693
694end 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.
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 4.1.1-dev2.
11-- Code generator VhdlAxiLiteWrapperGenerator version 1.0.0.
12-- Generated 2023-12-04 10:43 from file regs_counter.toml at commit d6ece437d0e3b2bc.
13-- Register hash 79eb071caf7e3f78ee67fa5265f7ef0edb0ea269.
14-- -----------------------------------------------------------------------------
15
16library ieee;
17use ieee.std_logic_1164.all;
18
19library axi;
20use axi.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;
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.
Dependencies
The VhdlRegisterPackageGenerator
and VhdlRecordPackageGenerator
packages
depend on reg_file_pkg.vhd
from the reg_file module of hdl-modules.
Can be downloaded from github here:
https://github.com/hdl-modules/hdl-modules/blob/main/modules/reg_file/src/reg_file_pkg.vhd
The VhdlSimulationPackageGenerator
package
furthermore depends 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 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 and axi library for more details.