Coverage for hdl_registers/generator/vhdl/test/test_register_vhdl_generator.py: 100%
96 statements
« prev ^ index » next coverage.py v7.8.0, created at 2025-04-29 06:41 +0000
« prev ^ index » next coverage.py v7.8.0, created at 2025-04-29 06:41 +0000
1# --------------------------------------------------------------------------------------------------
2# Copyright (c) Lukas Vik. All rights reserved.
3#
4# This file is part of the hdl-registers project, an HDL register generator fast enough to run
5# in real time.
6# https://hdl-registers.com
7# https://github.com/hdl-registers/hdl-registers
8# --------------------------------------------------------------------------------------------------
10"""
11Some limited unit tests that check the generated code.
12Note that the generated VHDL code is also simulated in a functional test.
13"""
15from pathlib import Path
17from tsfpga.system_utils import read_file
19from hdl_registers import HDL_REGISTERS_DOC
20from hdl_registers.generator.vhdl.axi_lite.wrapper import VhdlAxiLiteWrapperGenerator
21from hdl_registers.generator.vhdl.record_package import VhdlRecordPackageGenerator
22from hdl_registers.generator.vhdl.register_package import VhdlRegisterPackageGenerator
23from hdl_registers.generator.vhdl.simulation.check_package import (
24 VhdlSimulationCheckPackageGenerator,
25)
26from hdl_registers.generator.vhdl.simulation.read_write_package import (
27 VhdlSimulationReadWritePackageGenerator,
28)
29from hdl_registers.generator.vhdl.simulation.wait_until_package import (
30 VhdlSimulationWaitUntilPackageGenerator,
31)
32from hdl_registers.parser.toml import from_toml
33from hdl_registers.register_list import RegisterList
34from hdl_registers.register_modes import REGISTER_MODES
37def generate_all_vhdl_artifacts(register_list: RegisterList, output_folder: Path) -> None:
38 VhdlRegisterPackageGenerator(
39 register_list=register_list, output_folder=output_folder
40 ).create_if_needed()
42 VhdlRecordPackageGenerator(
43 register_list=register_list, output_folder=output_folder
44 ).create_if_needed()
46 VhdlAxiLiteWrapperGenerator(
47 register_list=register_list, output_folder=output_folder
48 ).create_if_needed()
50 VhdlSimulationReadWritePackageGenerator(
51 register_list=register_list, output_folder=output_folder
52 ).create_if_needed()
54 VhdlSimulationCheckPackageGenerator(
55 register_list=register_list, output_folder=output_folder
56 ).create_if_needed()
58 VhdlSimulationWaitUntilPackageGenerator(
59 register_list=register_list, output_folder=output_folder
60 ).create_if_needed()
63def get_strange_register_lists() -> list[RegisterList]:
64 """
65 Create some strange register lists for testing of niche cases.
66 """
67 result = []
69 def create_packages(direction, mode):
70 def append_register(data, name):
71 """
72 Append a register with some fields.
73 """
74 register = data.append_register(
75 name=f"{name}_{mode.shorthand}", mode=mode, description=""
76 )
78 register.append_integer(
79 name="integer", description="", min_value=-10, max_value=10, default_value=3
80 )
81 register.append_enumeration(
82 name="enumeration", description="", elements={"a": "", "b": ""}, default_value="b"
83 )
85 def append_registers(data):
86 """
87 Append some registers with some fields, either to a RegisterList or a RegisterArray.
88 """
89 append_register(data=data, name="first")
90 append_register(data=data, name="second")
92 # Some plain registers, in one direction only.
93 register_list = RegisterList(name=f"plain_only_{direction}")
94 append_registers(data=register_list)
95 result.append(register_list)
97 # Some register arrays, in one direction only.
98 register_list = RegisterList(name=f"array_only_{direction}")
99 register_array = register_list.append_register_array(name="apa", length=5, description="")
100 append_registers(data=register_array)
101 register_array = register_list.append_register_array(name="hest", length=10, description="")
102 append_registers(data=register_array)
103 result.append(register_list)
105 # Plain registers and some register arrays, in one direction only.
106 register_list = RegisterList(name=f"plain_and_array_only_{direction}")
107 append_registers(data=register_list)
108 register_array = register_list.append_register_array(name="apa", length=5, description="")
109 append_registers(data=register_array)
110 register_array = register_list.append_register_array(name="hest", length=10, description="")
111 append_registers(data=register_array)
112 result.append(register_list)
114 # Mode 'Read only' should give registers only in the 'up' direction'
115 create_packages(direction="up", mode=REGISTER_MODES["r"])
116 # Mode 'Write only' should give registers only in the 'down' direction'
117 create_packages(direction="down", mode=REGISTER_MODES["w"])
119 register_list = RegisterList(name="only_constants")
120 register_list.add_constant(name="first", value=123, description="")
121 register_list.add_constant(name="second", value=True, description="")
122 register_list.add_constant(name="third", value=5e30, description="")
123 register_list.add_constant(name="fourth", value=1e-12, description="")
124 result.append(register_list)
126 result.append(RegisterList(name="empty"))
128 return result
131def get_all_doc_register_lists() -> list[RegisterList]:
132 """
133 Get all register lists that are used for documentation.
134 """
135 return [
136 from_toml(name=toml_file.stem, toml_file=toml_file)
137 for toml_file in HDL_REGISTERS_DOC.glob("**/*.toml")
138 if "default_registers" not in toml_file.stem
139 ]
142def generate_strange_register_maps(output_path):
143 """
144 Generate register VHDL artifacts for some strange niche cases.
145 """
146 for register_list in get_strange_register_lists():
147 generate_all_vhdl_artifacts(register_list=register_list, output_folder=output_path)
150def _get_register_arrays_record_string(direction):
151 return (
152 f"records for the registers of each register array the are in the '{direction}' direction"
153 )
156def test_registers_only_in_up_direction_should_give_no_down_type_or_port(tmp_path):
157 generate_strange_register_maps(output_path=tmp_path)
159 for file_name in ["array_only_up", "plain_and_array_only_up", "plain_only_up"]:
160 vhd = read_file(tmp_path / f"{file_name}_register_record_pkg.vhd")
162 assert f"{file_name}_regs_up_t" in vhd
163 assert f"{file_name}_regs_down_t" not in vhd
165 # If there are no arrays there should be no records for arrays, and this comment shall not
166 # be present.
167 string = _get_register_arrays_record_string("up")
168 if "array" in file_name:
169 assert string in vhd
170 else:
171 assert string not in vhd
173 # The 'down' comment shall never be present since we have no 'down' registers.
174 string = _get_register_arrays_record_string("down")
175 assert string not in vhd
177 vhd = read_file(tmp_path / f"{file_name}_register_file_axi_lite.vhd")
179 assert "regs_up : in" in vhd
180 assert "regs_down : out" not in vhd
182 assert "reg_was_read : out" in vhd
183 assert "reg_was_written : out" not in vhd
186def test_registers_only_in_down_direction_should_give_no_down_type_or_port(tmp_path):
187 generate_strange_register_maps(output_path=tmp_path)
189 for file_name in ["array_only_down", "plain_and_array_only_down", "plain_only_down"]:
190 vhd = read_file(tmp_path / f"{file_name}_register_record_pkg.vhd")
192 assert f"{file_name}_regs_up_t" not in vhd
193 assert f"{file_name}_regs_down_t" in vhd
195 # If there are no arrays there should be no records for arrays, and this comment shall not
196 # be present.
197 string = _get_register_arrays_record_string("down")
198 if "array" in file_name:
199 assert string in vhd
200 else:
201 assert string not in vhd
203 # The 'up' comment shall never be present since we have no 'up' registers.
204 string = _get_register_arrays_record_string("up")
205 assert string not in vhd
207 vhd = read_file(tmp_path / f"{file_name}_register_file_axi_lite.vhd")
209 assert "regs_up : in" not in vhd
210 assert "regs_down : out" in vhd
212 assert "reg_was_read : out" not in vhd
213 assert "reg_was_written : out" in vhd