Coverage for hdl_registers/field/test/test_bit_vector.py: 100%

124 statements  

« prev     ^ index     » next       coverage.py v7.6.12, created at 2025-03-12 11:11 +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# -------------------------------------------------------------------------------------------------- 

9 

10import pytest 

11 

12from hdl_registers.field.bit_vector import BitVector 

13from hdl_registers.field.numerical_interpretation import ( 

14 Signed, 

15 SignedFixedPoint, 

16 Unsigned, 

17 UnsignedFixedPoint, 

18) 

19 

20 

21def test_get_value_plain(): 

22 field = BitVector(name="", base_index=2, description="", width=4, default_value="0000") 

23 

24 register_value = int("1110000_11", base=2) 

25 assert field.get_value(register_value) == 0 

26 

27 register_value = int("0001111_00", base=2) 

28 assert field.get_value(register_value) == 15 

29 

30 register_value = int("1010101_01", base=2) 

31 assert field.get_value(register_value) == 5 

32 

33 

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 

47 

48 

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 

55 

56 with pytest.raises(ValueError): 

57 bit_vector.set_value(0b111) 

58 

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 

63 

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 

68 

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") 

72 

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 

78 

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 

84 

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 

90 

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 

103 

104 

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 

109 

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 

120 

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 

131 

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 

142 

143 

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 ) 

149 

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")) 

154 

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")) 

159 

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")) 

164 

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")) 

169 

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")) 

174 

175 # Different numerical_interpretation 

176 field0 = BitVector( 

177 name="apa", 

178 base_index=0, 

179 description="", 

180 width=10, 

181 default_value="0" * 10, 

182 numerical_interpretation=UnsignedFixedPoint(max_bit_index=7, min_bit_index=-2), 

183 ) 

184 field1 = BitVector( 

185 name="apa", 

186 base_index=0, 

187 description="", 

188 width=10, 

189 default_value="0" * 10, 

190 numerical_interpretation=UnsignedFixedPoint(max_bit_index=7, min_bit_index=-2), 

191 ) 

192 field2 = BitVector( 

193 name="apa", 

194 base_index=0, 

195 description="", 

196 width=10, 

197 default_value="0" * 10, 

198 numerical_interpretation=UnsignedFixedPoint(max_bit_index=8, min_bit_index=-1), 

199 ) 

200 assert repr(field0) == repr(field1) != repr(field2) 

201 

202 

203def test_invalid_width(): 

204 with pytest.raises(TypeError) as exception_info: 

205 BitVector(name="foo", base_index=0, width="4", description="", default_value="0000") 

206 assert ( 

207 str(exception_info.value) 

208 == 'Bit vector "foo" should have integer value for "width". Got: "4".' 

209 ) 

210 

211 with pytest.raises(ValueError) as exception_info: 

212 BitVector(name="foo", base_index=0, width=33, description="", default_value="0") 

213 assert str(exception_info.value) == 'Invalid width for bit vector "foo". Got: "33".' 

214 

215 with pytest.raises(ValueError) as exception_info: 

216 BitVector(name="foo", base_index=0, width=0, description="", default_value="0") 

217 assert str(exception_info.value) == 'Invalid width for bit vector "foo". Got: "0".' 

218 

219 

220def test_invalid_default_value_should_raise_exception(): 

221 with pytest.raises(TypeError) as exception_info: 

222 BitVector(name="hest", base_index=0, description="", width=4, default_value=1111) 

223 assert str(exception_info.value) == ( 

224 'Bit vector "hest" should have string value for "default_value". Got: "1111"' 

225 ) 

226 

227 with pytest.raises(ValueError) as exception_info: 

228 BitVector(name="hest", base_index=0, description="", width=4, default_value="11") 

229 assert str(exception_info.value) == ( 

230 'Bit vector "hest" should have "default_value" of length 4. Got: "11".' 

231 ) 

232 

233 with pytest.raises(ValueError) as exception_info: 

234 BitVector(name="hest", base_index=0, description="", width=4, default_value="1121") 

235 assert str(exception_info.value) == ( 

236 'Bit vector "hest" invalid binary value for "default_value". Got: "1121".' 

237 ) 

238 

239 

240def test_can_update_default_value(): 

241 bit_vector = BitVector(name="hest", base_index=0, description="", width=4, default_value="1111") 

242 assert bit_vector.default_value == "1111" 

243 

244 bit_vector.default_value = "0000" 

245 assert bit_vector.default_value == "0000" 

246 

247 

248def test_updating_to_invalid_default_value_should_raise_exception(): 

249 # Create with a valid default_value 

250 bit_vector = BitVector(name="hest", base_index=0, description="", width=4, default_value="1111") 

251 

252 # Update to an invalid value 

253 with pytest.raises(TypeError) as exception_info: 

254 bit_vector.default_value = 1111 

255 assert str(exception_info.value) == ( 

256 'Bit vector "hest" should have string value for "default_value". Got: "1111"' 

257 ) 

258 

259 

260def test_default_value_uint(): 

261 bit_vector = BitVector(name="apa", base_index=0, description="", width=4, default_value="0000") 

262 assert bit_vector.default_value_uint == 0 

263 

264 bit_vector.default_value = "0010" 

265 assert bit_vector.default_value_uint == 2 

266 

267 bit_vector.default_value = "1001" 

268 assert bit_vector.default_value_uint == 9 

269 

270 

271def test_numeric_interpretation(): 

272 bit_vector = BitVector(name="", base_index=5, description="", width=4, default_value="1111") 

273 assert isinstance(bit_vector.numerical_interpretation, Unsigned) 

274 assert bit_vector.numerical_interpretation.bit_width == 4 

275 

276 numerical_interpretation = Signed(bit_width=10) 

277 bit_vector = BitVector( 

278 name="", 

279 base_index=0, 

280 description="", 

281 width=10, 

282 default_value="1111111111", 

283 numerical_interpretation=numerical_interpretation, 

284 ) 

285 assert bit_vector.numerical_interpretation is numerical_interpretation 

286 

287 

288def test_invalid_numerical_interpretation_width_should_raise_exception(): 

289 def test(numerical_interpretation): 

290 with pytest.raises(ValueError) as exception_info: 

291 BitVector( 

292 name="apa", 

293 base_index=0, 

294 description="", 

295 width=4, 

296 default_value="1111", 

297 numerical_interpretation=numerical_interpretation, 

298 ) 

299 

300 bit_width = ( 

301 numerical_interpretation.integer_bit_width + numerical_interpretation.fraction_bit_width 

302 ) 

303 expected = ( 

304 f'Inconsistent width for bit vector "apa". ' 

305 f'Field is "4" bits, numerical interpretation specification is "{bit_width}".' 

306 ) 

307 assert str(exception_info.value) == expected 

308 

309 test(SignedFixedPoint(max_bit_index=7, min_bit_index=0)) 

310 test(UnsignedFixedPoint(max_bit_index=9, min_bit_index=-3)) 

311 

312 test(SignedFixedPoint(max_bit_index=5, min_bit_index=0)) 

313 test(UnsignedFixedPoint(max_bit_index=3, min_bit_index=-3))