Coverage for hdl_registers/field/test/test_bit_vector.py: 100%
145 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
12from hdl_registers.field.bit_vector import BitVector
13from hdl_registers.field.numerical_interpretation import (
14 Signed,
15 SignedFixedPoint,
16 Unsigned,
17 UnsignedFixedPoint,
18)
21def test_get_value_plain():
22 field = BitVector(name="", base_index=2, description="", width=4, default_value="0000")
24 register_value = int("1110000_11", base=2)
25 assert field.get_value(register_value) == 0
27 register_value = int("0001111_00", base=2)
28 assert field.get_value(register_value) == 15
30 register_value = int("1010101_01", base=2)
31 assert field.get_value(register_value) == 5
34def test_get_value_fixed():
35 field = BitVector(
36 name="",
37 base_index=2,
38 description="",
39 width=16,
40 default_value="0" * 16,
41 numerical_interpretation=SignedFixedPoint.from_bit_widths(
42 integer_bit_width=8, fraction_bit_width=8
43 ),
44 )
45 register_value = 0b11111111_00000011_11111111_11111100
46 assert field.get_value(register_value) == -0.00390625
49def test_set_value():
50 bit_vector = BitVector(
51 name="", base_index=0, description="", width=2, default_value=format(0, "02b")
52 )
53 assert bit_vector.set_value(0b10) == 0b10
54 assert bit_vector.set_value(0b11) == 0b11
56 with pytest.raises(ValueError):
57 bit_vector.set_value(0b111)
59 bit_vector = BitVector(
60 name="", base_index=2, description="", width=2, default_value=format(0, "02b")
61 )
62 assert bit_vector.set_value(0b10) == 0b10_00
64 bit_vector = BitVector(
65 name="", base_index=3, description="", width=4, default_value=format(0, "04b")
66 )
67 assert bit_vector.set_value(0b1111) == 0b1111_000
69 bit_vector0 = BitVector(name="", base_index=0, description="", width=2, default_value="00")
70 bit_vector1 = BitVector(name="", base_index=2, description="", width=4, default_value="0000")
71 bit_vector2 = BitVector(name="", base_index=6, description="", width=3, default_value="000")
73 register_value = int("111000011", base=2)
74 value0 = bit_vector0.set_value(bit_vector0.get_value(register_value))
75 value1 = bit_vector1.set_value(bit_vector1.get_value(register_value))
76 value2 = bit_vector2.set_value(bit_vector2.get_value(register_value))
77 assert value0 | value1 | value2 == register_value
79 register_value = int("000111100", base=2)
80 value0 = bit_vector0.set_value(bit_vector0.get_value(register_value))
81 value1 = bit_vector1.set_value(bit_vector1.get_value(register_value))
82 value2 = bit_vector2.set_value(bit_vector2.get_value(register_value))
83 assert value0 | value1 | value2 == register_value
85 register_value = int("101010101", base=2)
86 value0 = bit_vector0.set_value(bit_vector0.get_value(register_value))
87 value1 = bit_vector1.set_value(bit_vector1.get_value(register_value))
88 value2 = bit_vector2.set_value(bit_vector2.get_value(register_value))
89 assert value0 | value1 | value2 == register_value
91 # Test numerical_interpretation
92 field = BitVector(
93 name="",
94 base_index=2,
95 description="",
96 width=16,
97 default_value="0" * 16,
98 numerical_interpretation=SignedFixedPoint.from_bit_widths(
99 integer_bit_width=8, fraction_bit_width=8
100 ),
101 )
102 assert field.set_value(-0.00390625) == 0b11_11111111_11111100
105def test_min_and_max_value():
106 bit_vector = BitVector(name="", base_index=0, description="", width=4, default_value="0000")
107 assert bit_vector.numerical_interpretation.min_value == 0
108 assert bit_vector.numerical_interpretation.max_value == 15
110 bit_vector = BitVector(
111 name="",
112 base_index=0,
113 description="",
114 width=4,
115 default_value="0000",
116 numerical_interpretation=Signed(bit_width=4),
117 )
118 assert bit_vector.numerical_interpretation.min_value == -8
119 assert bit_vector.numerical_interpretation.max_value == 7
121 bit_vector = BitVector(
122 name="",
123 base_index=0,
124 description="",
125 width=4,
126 default_value="0000",
127 numerical_interpretation=UnsignedFixedPoint(1, -2),
128 )
129 assert bit_vector.numerical_interpretation.min_value == 0
130 assert bit_vector.numerical_interpretation.max_value == 3.75
132 bit_vector = BitVector(
133 name="",
134 base_index=0,
135 description="",
136 width=4,
137 default_value="0000",
138 numerical_interpretation=SignedFixedPoint(1, -2),
139 )
140 assert bit_vector.numerical_interpretation.min_value == -2
141 assert bit_vector.numerical_interpretation.max_value == 1.75
144def test_repr():
145 # Check that repr is an actual representation, not just "X object at 0xABCDEF"
146 assert "apa" in repr(
147 BitVector(name="apa", base_index=0, description="", width=1, default_value="0")
148 )
150 # Different name
151 assert repr(
152 BitVector(name="apa", base_index=0, description="", width=1, default_value="0")
153 ) != repr(BitVector(name="hest", base_index=0, description="", width=1, default_value="0"))
155 # Different base_index
156 assert repr(
157 BitVector(name="apa", base_index=0, description="", width=1, default_value="0")
158 ) != repr(BitVector(name="apa", base_index=1, description="", width=1, default_value="0"))
160 # Different description
161 assert repr(
162 BitVector(name="apa", base_index=0, description="Blah", width=1, default_value="0")
163 ) != repr(BitVector(name="apa", base_index=0, description="Gaah", width=1, default_value="0"))
165 # Different width
166 assert repr(
167 BitVector(name="apa", base_index=0, description="", width=1, default_value="1")
168 ) != repr(BitVector(name="apa", base_index=0, description="", width=2, default_value="11"))
170 # Different default_value
171 assert repr(
172 BitVector(name="apa", base_index=0, description="", width=1, default_value="1")
173 ) != repr(BitVector(name="apa", base_index=0, description="", width=1, default_value="0"))
175 # Same default_value but different representation in argument
176 assert repr(
177 BitVector(name="apa", base_index=0, description="", width=4, default_value="1101")
178 ) == repr(BitVector(name="apa", base_index=0, description="", width=4, default_value=13))
180 # Different numerical_interpretation
181 field0 = BitVector(
182 name="apa",
183 base_index=0,
184 description="",
185 width=10,
186 default_value="0" * 10,
187 numerical_interpretation=UnsignedFixedPoint(max_bit_index=7, min_bit_index=-2),
188 )
189 field1 = BitVector(
190 name="apa",
191 base_index=0,
192 description="",
193 width=10,
194 default_value="0" * 10,
195 numerical_interpretation=UnsignedFixedPoint(max_bit_index=7, min_bit_index=-2),
196 )
197 field2 = BitVector(
198 name="apa",
199 base_index=0,
200 description="",
201 width=10,
202 default_value="0" * 10,
203 numerical_interpretation=UnsignedFixedPoint(max_bit_index=8, min_bit_index=-1),
204 )
205 assert repr(field0) == repr(field1) != repr(field2)
208def test_invalid_width():
209 with pytest.raises(TypeError) as exception_info:
210 BitVector(name="foo", base_index=0, width="4", description="", default_value="0000")
211 assert (
212 str(exception_info.value)
213 == 'Bit vector "foo" should have integer value for "width". Got: "4".'
214 )
216 with pytest.raises(ValueError) as exception_info:
217 BitVector(name="foo", base_index=0, width=33, description="", default_value="0")
218 assert str(exception_info.value) == 'Invalid width for bit vector "foo". Got: "33".'
220 with pytest.raises(ValueError) as exception_info:
221 BitVector(name="foo", base_index=0, width=0, description="", default_value="0")
222 assert str(exception_info.value) == 'Invalid width for bit vector "foo". Got: "0".'
225def test_invalid_default_value_should_raise_exception():
226 with pytest.raises(TypeError) as exception_info:
227 BitVector(name="hest", base_index=0, description="", width=4, default_value=TypeError)
228 assert str(exception_info.value) == (
229 'Bit vector "hest" should have string or numeric value for "default_value". '
230 "Got: \"<class 'TypeError'>\"."
231 )
234def test_can_update_default_value():
235 bit_vector = BitVector(name="hest", base_index=0, description="", width=4, default_value="1111")
236 assert bit_vector.default_value == "1111"
238 bit_vector.default_value = 3
239 assert bit_vector.default_value == "0011"
242def test_updating_to_invalid_default_value_should_raise_exception():
243 # Create with a valid default_value
244 bit_vector = BitVector(name="hest", base_index=0, description="", width=4, default_value="1111")
246 # Update to an invalid value
247 with pytest.raises(TypeError) as exception_info:
248 bit_vector.default_value = TypeError
249 assert str(exception_info.value) == (
250 'Bit vector "hest" should have string or numeric value for "default_value". '
251 "Got: \"<class 'TypeError'>\"."
252 )
255def test_setting_non_binary_default_value_should_raise_exception():
256 # Update to an invalid value
257 with pytest.raises(ValueError) as exception_info:
258 BitVector(name="hest", base_index=0, description="", width=4, default_value="1211")
259 assert str(exception_info.value) == (
260 'Bit vector "hest" invalid binary "default_value". Got: "1211".'
261 )
264def test_default_value_uint():
265 bit_vector = BitVector(name="apa", base_index=0, description="", width=4, default_value="0000")
266 assert bit_vector.default_value_uint == 0
268 bit_vector.default_value = "0010"
269 assert bit_vector.default_value_uint == 2
271 bit_vector.default_value = "1001"
272 assert bit_vector.default_value_uint == 9
275def test_default_value_signed():
276 bit_vector = BitVector(
277 name="apa",
278 base_index=0,
279 description="",
280 width=4,
281 default_value=-7,
282 numerical_interpretation=Signed(bit_width=4),
283 )
284 assert bit_vector.default_value == "1001"
285 assert bit_vector.default_value_uint == 9
288def test_default_value_ufixed():
289 bit_vector = BitVector(
290 name="apa",
291 base_index=0,
292 description="",
293 width=6,
294 default_value=7.75,
295 numerical_interpretation=SignedFixedPoint(max_bit_index=3, min_bit_index=-2),
296 )
297 assert bit_vector.default_value == "011111"
298 assert bit_vector.default_value_uint == 31
301def test_default_value_sfixed():
302 bit_vector = BitVector(
303 name="apa",
304 base_index=0,
305 description="",
306 width=5,
307 default_value=-7.5,
308 numerical_interpretation=SignedFixedPoint(max_bit_index=3, min_bit_index=-1),
309 )
310 assert bit_vector.default_value == "10001"
311 assert bit_vector.default_value_uint == 17
314def test_default_value_fixed_point_that_does_not_fit_perfectly_should_raise_exception():
315 bit_vector = BitVector(
316 name="apa",
317 base_index=0,
318 description="",
319 width=6,
320 default_value=0,
321 numerical_interpretation=SignedFixedPoint(max_bit_index=3, min_bit_index=-2),
322 )
323 bit_vector.default_value = 7.75
325 with pytest.raises(ValueError) as exception_info:
326 bit_vector.default_value = 7.76
327 assert str(exception_info.value) == (
328 'Bit vector "apa" should have "default_value" that fits in 6 SignedFixedPoint bits. '
329 'Got: "7.76".'
330 )
333def test_default_value_float_value_to_integer_should_raise_exception():
334 with pytest.raises(ValueError) as exception_info:
335 BitVector(name="apa", base_index=0, description="", width=6, default_value=3.5)
336 assert str(exception_info.value) == (
337 'Bit vector "apa" should have "default_value" that fits in 6 Unsigned bits. Got: "3.5".'
338 )
341def test_numeric_interpretation():
342 bit_vector = BitVector(name="", base_index=5, description="", width=4, default_value="1111")
343 assert isinstance(bit_vector.numerical_interpretation, Unsigned)
344 assert bit_vector.numerical_interpretation.bit_width == 4
346 numerical_interpretation = Signed(bit_width=10)
347 bit_vector = BitVector(
348 name="",
349 base_index=0,
350 description="",
351 width=10,
352 default_value="1111111111",
353 numerical_interpretation=numerical_interpretation,
354 )
355 assert bit_vector.numerical_interpretation is numerical_interpretation
358def test_invalid_numerical_interpretation_width_should_raise_exception():
359 def test(numerical_interpretation):
360 with pytest.raises(ValueError) as exception_info:
361 BitVector(
362 name="apa",
363 base_index=0,
364 description="",
365 width=4,
366 default_value="1111",
367 numerical_interpretation=numerical_interpretation,
368 )
370 bit_width = (
371 numerical_interpretation.integer_bit_width + numerical_interpretation.fraction_bit_width
372 )
373 expected = (
374 f'Inconsistent width for bit vector "apa". '
375 f'Field is "4" bits, numerical interpretation specification is "{bit_width}".'
376 )
377 assert str(exception_info.value) == expected
379 test(SignedFixedPoint(max_bit_index=7, min_bit_index=0))
380 test(UnsignedFixedPoint(max_bit_index=9, min_bit_index=-3))
382 test(SignedFixedPoint(max_bit_index=5, min_bit_index=0))
383 test(UnsignedFixedPoint(max_bit_index=3, min_bit_index=-3))