Coverage for hdl_registers/generator/systemverilog/axi_lite/test/test_register_file.py: 100%
134 statements
« prev ^ index » next coverage.py v7.10.7, created at 2025-10-13 20:52 +0000
« prev ^ index » next coverage.py v7.10.7, created at 2025-10-13 20:52 +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# --------------------------------------------------------------------------------------------------
10import pytest
11from tsfpga.system_utils import create_file, read_file
13from hdl_registers.field.enumeration import Enumeration
14from hdl_registers.field.integer import Integer
15from hdl_registers.field.numerical_interpretation import (
16 Signed,
17 SignedFixedPoint,
18 UnsignedFixedPoint,
19)
20from hdl_registers.generator.systemverilog.axi_lite.register_file import (
21 SystemVerilogAxiLiteGenerator,
22)
23from hdl_registers.register_list import RegisterList
24from hdl_registers.register_modes import REGISTER_MODES
27def get_basic_register_list(path=None):
28 source_definition_file = None if path is None else path
29 register_list = RegisterList(name="caesar", source_definition_file=source_definition_file)
31 register = register_list.append_register(name="reg0", mode=REGISTER_MODES["w"], description="")
32 register.append_bit(name="bit0", description="", default_value="0")
33 register.append_bit(name="bit1", description="", default_value="1")
34 register.append_bit_vector(name="bit_vector0", description="", width=4, default_value="1101")
35 register.append_bit_vector(
36 name="bit_vector1",
37 description="",
38 width=4,
39 default_value="1001",
40 numerical_interpretation=Signed(bit_width=4),
41 )
42 register.append_bit_vector(
43 name="bit_vector2",
44 description="",
45 width=4,
46 default_value="1101",
47 numerical_interpretation=UnsignedFixedPoint(1, -2),
48 )
49 register.append_bit_vector(
50 name="bit_vector3",
51 description="",
52 width=4,
53 default_value="1101",
54 numerical_interpretation=SignedFixedPoint(2, -1),
55 )
56 register.append_integer(
57 name="int0", min_value=3, max_value=16383, default_value=16377, description=""
58 )
60 register = register_list.append_register(name="reg1", mode=REGISTER_MODES["r"], description="")
61 register.append_enumeration(
62 name="enum0",
63 description="",
64 elements={"element0": "", "element1": "", "element2": "", "element3": "", "element4": ""},
65 default_value="element1",
66 )
67 register.append_bit_vector(name="bit_vector4", description="", width=1, default_value="0")
68 register.append_bit(name="bit2", description="", default_value="1")
70 register = register_list.append_register(
71 name="reg2", mode=REGISTER_MODES["r_w"], description=""
72 )
73 register.append_bit_vector(name="bit_vector5", description="", width=6, default_value="010101")
74 register.append_enumeration(
75 name="enum1", description="", elements={"element5": ""}, default_value="element5"
76 )
78 return register_list
81def test_basic_register_list(tmp_path):
82 generator = SystemVerilogAxiLiteGenerator(
83 register_list=get_basic_register_list(), output_folder=tmp_path
84 )
85 generator.create()
87 for generated_file in generator.output_files:
88 print(generated_file)
91def test_create_if_needed(tmp_path):
92 generator = SystemVerilogAxiLiteGenerator(
93 register_list=get_basic_register_list(), output_folder=tmp_path
94 )
96 def create(expect_create: bool = True):
97 created, _ = generator.create_if_needed()
98 assert created == expect_create
100 create()
101 create(expect_create=False)
103 sv = read_file(generator.output_file)
104 create_file(generator.output_file, sv.replace("hdl-registers version ", "AAAAAAA"))
105 create()
106 create(expect_create=False)
108 (tmp_path / "caesar_register_file_axi_lite.sv").unlink()
109 create()
110 create(expect_create=False)
112 (tmp_path / "caesar_register_file_axi_lite_pkg.sv").unlink()
113 create()
114 create(expect_create=False)
117def test_flatten(tmp_path):
118 generator = SystemVerilogAxiLiteGenerator(
119 register_list=get_basic_register_list(), output_folder=tmp_path
120 )
122 interface = "axi4lite_intf.slave s_axil,"
123 flattened = "input wire s_axil_awvalid,"
125 generator.create(flatten_axi_lite=True)
126 sv = read_file(generator.output_file)
128 assert interface not in sv
129 assert flattened in sv
131 generator.create(flatten_axi_lite=False)
132 sv = read_file(generator.output_file)
134 assert interface in sv
135 assert flattened not in sv
138def test_with_and_without_source_definition_file(tmp_path):
139 """
140 The name of the source definition file does not seem to appear anywhere in the
141 generated SystemVerilog code.
142 But we set it anyway since it's part of the API.
143 In SystemRDL it is required, but in hdl-registers it is optional, so we test both cases.
144 """
145 SystemVerilogAxiLiteGenerator(
146 register_list=get_basic_register_list(path=tmp_path), output_folder=tmp_path
147 ).create()
148 SystemVerilogAxiLiteGenerator(
149 register_list=get_basic_register_list(), output_folder=tmp_path
150 ).create()
153def test_default_values_on_reset(tmp_path):
154 register_list = get_basic_register_list()
155 sv = read_file(
156 SystemVerilogAxiLiteGenerator(register_list=register_list, output_folder=tmp_path).create()
157 )
159 for register in register_list.register_objects:
160 for field in register.fields:
161 reset_assign = f"""
162 if(rst) begin
163 field_storage.{register.name}.{field.name}.value <="""
165 if register.mode.software_can_write:
166 default_value_int = (
167 field.default_value.value
168 if isinstance(field, Enumeration)
169 else field.default_value
170 if isinstance(field, Integer)
171 else int(field.default_value, 2)
172 )
173 assert f"{reset_assign} {field.width}'h{default_value_int:x};\n" in sv
174 else:
175 assert reset_assign not in sv
178def test_field_bit_indexes(tmp_path):
179 register_list = get_basic_register_list(path=tmp_path)
180 sv = read_file(
181 SystemVerilogAxiLiteGenerator(register_list=register_list, output_folder=tmp_path).create()
182 )
184 for register in register_list.register_objects:
185 for field in register.fields:
186 bits = f"{field.base_index + field.width - 1}:{field.base_index}"
188 if register.mode.software_can_write:
189 assert (
190 f"next_c = "
191 f"(field_storage.{register.name}.{field.name}.value "
192 f"& ~decoded_wr_biten[{bits}])"
193 ) in sv
195 if register.mode.software_can_read:
196 value_source = "field_storage" if register.mode.software_can_write else "hwif_in"
197 assert (
198 f"[{bits}] = (decoded_reg_strb.{register.name} && !decoded_req_is_wr) ? "
199 f"{value_source}.{register.name}.{field.name}."
200 ) in sv
203def test_enumeration_naming_and_encoding(tmp_path):
204 SystemVerilogAxiLiteGenerator(
205 register_list=get_basic_register_list(path=tmp_path), output_folder=tmp_path
206 ).create()
207 sv = read_file(tmp_path / "caesar_register_file_axi_lite_pkg.sv")
209 assert (
210 """
211 typedef enum logic [2:0] {
212 caesar_reg1_enum0__element0 = 'h0,
213 caesar_reg1_enum0__element1 = 'h1,
214 caesar_reg1_enum0__element2 = 'h2,
215 caesar_reg1_enum0__element3 = 'h3,
216 caesar_reg1_enum0__element4 = 'h4
217 } caesar_reg1_enum0_e;
219 typedef enum logic {
220 caesar_reg2_enum1__element5 = 'h0
221 } caesar_reg2_enum1_e;
222"""
223 in sv
224 )
227def test_empty_register_list(tmp_path):
228 register_list = RegisterList(name="empty")
229 _test_empty_register_list(register_list=register_list, tmp_path=tmp_path)
232def _test_empty_register_list(register_list, tmp_path, extra=""):
233 with pytest.raises(ValueError) as exception_info:
234 SystemVerilogAxiLiteGenerator(register_list=register_list, output_folder=tmp_path).create()
235 assert str(exception_info.value) == (
236 f'Error while translating "empty"{extra}: '
237 "SystemVerilog generator requires at least one register."
238 )
241def test_error_message_with_and_without_source_definition_file(tmp_path):
242 register_list = RegisterList(name="empty")
243 _test_empty_register_list(register_list=register_list, tmp_path=tmp_path)
245 register_list = RegisterList(name="empty", source_definition_file=tmp_path)
246 _test_empty_register_list(
247 register_list=register_list, tmp_path=tmp_path, extra=f" in {tmp_path}"
248 )
251def test_register_array(tmp_path):
252 register_list = get_basic_register_list(path=tmp_path)
253 register_list.append_register_array(name="a", length=2, description="").append_register(
254 "b", mode=REGISTER_MODES["r"], description=""
255 )
257 with pytest.raises(ValueError) as exception_info:
258 SystemVerilogAxiLiteGenerator(register_list=register_list, output_folder=tmp_path).create()
259 assert str(exception_info.value) == (
260 f'Error while translating "caesar.a" in {tmp_path}: '
261 "SystemVerilog generator does not support register arrays."
262 )
265def test_empty_register(tmp_path):
266 register_list = get_basic_register_list(path=tmp_path)
267 register_list.append_register("b", mode=REGISTER_MODES["r"], description="")
269 with pytest.raises(ValueError) as exception_info:
270 SystemVerilogAxiLiteGenerator(register_list=register_list, output_folder=tmp_path).create()
271 assert str(exception_info.value) == (
272 f'Error while translating "caesar.b" in {tmp_path}: '
273 "SystemVerilog generator requires at least one field per register."
274 )
277def test_signed_integer_field(tmp_path):
278 register_list = get_basic_register_list(path=tmp_path)
279 register_list.append_register("b", mode=REGISTER_MODES["r"], description="").append_integer(
280 name="c", min_value=-1, max_value=1, default_value=0, description=""
281 )
283 with pytest.raises(ValueError) as exception_info:
284 SystemVerilogAxiLiteGenerator(register_list=register_list, output_folder=tmp_path).create()
285 assert str(exception_info.value) == (
286 f'Error while translating "caesar.b.c" in {tmp_path}: '
287 "SystemVerilog generator does not support signed integer fields."
288 )
291def test_constant(tmp_path):
292 register_list = get_basic_register_list(path=tmp_path)
293 register_list.add_constant(name="c", value=42, description="")
295 with pytest.raises(ValueError) as exception_info:
296 SystemVerilogAxiLiteGenerator(register_list=register_list, output_folder=tmp_path).create()
297 assert str(exception_info.value) == (
298 f'Error while translating "caesar" in {tmp_path}: '
299 "SystemVerilog generator does not support constants."
300 )
303def test_register_mode_r_wpulse(tmp_path):
304 def run_test(mode):
305 register_list = get_basic_register_list(path=tmp_path)
306 register_list.append_register(
307 name="a", mode=REGISTER_MODES[mode], description=""
308 ).append_bit(name="b", description="", default_value="1")
310 with pytest.raises(ValueError) as exception_info:
311 SystemVerilogAxiLiteGenerator(
312 register_list=register_list, output_folder=tmp_path
313 ).create()
314 assert str(exception_info.value) == (
315 f'Error while translating "caesar.a" in {tmp_path}: '
316 "SystemVerilog generator does not support "
317 f"register mode: RegisterMode(shorthand={mode})"
318 )
320 run_test("r_wpulse")
321 run_test("wpulse")