Coverage for hdl_registers/generator/systemverilog/axi_lite/test/test_register_file.py: 100%
136 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# --------------------------------------------------------------------------------------------------
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 default_value_int = (
162 field.default_value.value
163 if isinstance(field, Enumeration)
164 else field.default_value
165 if isinstance(field, Integer)
166 else int(field.default_value, 2)
167 )
168 default_value_hex = hex(default_value_int)[2:]
170 print(field)
171 reset_assign = f"""
172 if(rst) begin
173 field_storage.{register.name}.{field.name}.value <="""
175 if register.mode.software_can_write:
176 assert f"{reset_assign} {field.width}'h{default_value_hex};\n" in sv
177 else:
178 assert reset_assign not in sv
181def test_field_bit_indexes(tmp_path):
182 register_list = get_basic_register_list(path=tmp_path)
183 sv = read_file(
184 SystemVerilogAxiLiteGenerator(register_list=register_list, output_folder=tmp_path).create()
185 )
187 for register in register_list.register_objects:
188 for field in register.fields:
189 bits = f"{field.base_index + field.width - 1}:{field.base_index}"
191 if register.mode.software_can_write:
192 assert (
193 f"next_c = "
194 f"(field_storage.{register.name}.{field.name}.value "
195 f"& ~decoded_wr_biten[{bits}])"
196 ) in sv
198 if register.mode.software_can_read:
199 value_source = "field_storage" if register.mode.software_can_write else "hwif_in"
200 assert (
201 f"[{bits}] = (decoded_reg_strb.{register.name} && !decoded_req_is_wr) ? "
202 f"{value_source}.{register.name}.{field.name}."
203 ) in sv
206def test_enumeration_naming_and_encoding(tmp_path):
207 SystemVerilogAxiLiteGenerator(
208 register_list=get_basic_register_list(path=tmp_path), output_folder=tmp_path
209 ).create()
210 sv = read_file(tmp_path / "caesar_register_file_axi_lite_pkg.sv")
212 assert (
213 """
214 typedef enum logic [2:0] {
215 caesar_reg1_enum0__element0 = 'h0,
216 caesar_reg1_enum0__element1 = 'h1,
217 caesar_reg1_enum0__element2 = 'h2,
218 caesar_reg1_enum0__element3 = 'h3,
219 caesar_reg1_enum0__element4 = 'h4
220 } caesar_reg1_enum0_e;
222 typedef enum logic {
223 caesar_reg2_enum1__element5 = 'h0
224 } caesar_reg2_enum1_e;
225"""
226 in sv
227 )
230def test_empty_register_list(tmp_path):
231 register_list = RegisterList(name="empty")
232 _test_empty_register_list(register_list=register_list, tmp_path=tmp_path)
235def _test_empty_register_list(register_list, tmp_path, extra=""):
236 with pytest.raises(ValueError) as exception_info:
237 SystemVerilogAxiLiteGenerator(register_list=register_list, output_folder=tmp_path).create()
238 assert str(exception_info.value) == (
239 f'Error while translating "empty"{extra}: '
240 "SystemVerilog generator requires at least one register."
241 )
244def test_error_message_with_and_without_source_definition_file(tmp_path):
245 register_list = RegisterList(name="empty")
246 _test_empty_register_list(register_list=register_list, tmp_path=tmp_path)
248 register_list = RegisterList(name="empty", source_definition_file=tmp_path)
249 _test_empty_register_list(
250 register_list=register_list, tmp_path=tmp_path, extra=f" in {tmp_path}"
251 )
254def test_register_array(tmp_path):
255 register_list = get_basic_register_list(path=tmp_path)
256 register_list.append_register_array(name="a", length=2, description="").append_register(
257 "b", mode=REGISTER_MODES["r"], description=""
258 )
260 with pytest.raises(ValueError) as exception_info:
261 SystemVerilogAxiLiteGenerator(register_list=register_list, output_folder=tmp_path).create()
262 assert str(exception_info.value) == (
263 f'Error while translating "caesar.a" in {tmp_path}: '
264 "SystemVerilog generator does not support register arrays."
265 )
268def test_empty_register(tmp_path):
269 register_list = get_basic_register_list(path=tmp_path)
270 register_list.append_register("b", mode=REGISTER_MODES["r"], description="")
272 with pytest.raises(ValueError) as exception_info:
273 SystemVerilogAxiLiteGenerator(register_list=register_list, output_folder=tmp_path).create()
274 assert str(exception_info.value) == (
275 f'Error while translating "caesar.b" in {tmp_path}: '
276 "SystemVerilog generator requires at least one field per register."
277 )
280def test_signed_integer_field(tmp_path):
281 register_list = get_basic_register_list(path=tmp_path)
282 register_list.append_register("b", mode=REGISTER_MODES["r"], description="").append_integer(
283 name="c", min_value=-1, max_value=1, default_value=0, description=""
284 )
286 with pytest.raises(ValueError) as exception_info:
287 SystemVerilogAxiLiteGenerator(register_list=register_list, output_folder=tmp_path).create()
288 assert str(exception_info.value) == (
289 f'Error while translating "caesar.b.c" in {tmp_path}: '
290 "SystemVerilog generator does not support signed integer fields."
291 )
294def test_constant(tmp_path):
295 register_list = get_basic_register_list(path=tmp_path)
296 register_list.add_constant(name="c", value=42, description="")
298 with pytest.raises(ValueError) as exception_info:
299 SystemVerilogAxiLiteGenerator(register_list=register_list, output_folder=tmp_path).create()
300 assert str(exception_info.value) == (
301 f'Error while translating "caesar" in {tmp_path}: '
302 "SystemVerilog generator does not support constants."
303 )
306def test_register_mode_r_wpulse(tmp_path):
307 def run_test(mode):
308 register_list = get_basic_register_list(path=tmp_path)
309 register_list.append_register(
310 name="a", mode=REGISTER_MODES[mode], description=""
311 ).append_bit(name="b", description="", default_value="1")
313 with pytest.raises(ValueError) as exception_info:
314 SystemVerilogAxiLiteGenerator(
315 register_list=register_list, output_folder=tmp_path
316 ).create()
317 assert str(exception_info.value) == (
318 f'Error while translating "caesar.a" in {tmp_path}: '
319 "SystemVerilog generator does not support "
320 f"register mode: RegisterMode(shorthand={mode})"
321 )
323 run_test("r_wpulse")
324 run_test("wpulse")