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

124 statements  

« prev     ^ index     » next       coverage.py v7.6.8, created at 2024-12-01 20:50 +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 

10# Third party libraries 

11import pytest 

12 

13# First party libraries 

14from hdl_registers.field.bit_vector import BitVector 

15from hdl_registers.field.numerical_interpretation import ( 

16 Signed, 

17 SignedFixedPoint, 

18 Unsigned, 

19 UnsignedFixedPoint, 

20) 

21 

22 

23def test_get_value_plain(): 

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

25 

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

27 assert field.get_value(register_value) == 0 

28 

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

30 assert field.get_value(register_value) == 15 

31 

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

33 assert field.get_value(register_value) == 5 

34 

35 

36def test_get_value_fixed(): 

37 field = BitVector( 

38 name="", 

39 base_index=2, 

40 description="", 

41 width=16, 

42 default_value="0" * 16, 

43 numerical_interpretation=SignedFixedPoint.from_bit_widths( 

44 integer_bit_width=8, fraction_bit_width=8 

45 ), 

46 ) 

47 register_value = 0b11111111_00000011_11111111_11111100 

48 assert field.get_value(register_value) == -0.00390625 

49 

50 

51def test_set_value(): 

52 bit_vector = BitVector( 

53 name="", base_index=0, description="", width=2, default_value=format(0, "02b") 

54 ) 

55 assert bit_vector.set_value(0b10) == 0b10 

56 assert bit_vector.set_value(0b11) == 0b11 

57 

58 with pytest.raises(ValueError): 

59 bit_vector.set_value(0b111) 

60 

61 bit_vector = BitVector( 

62 name="", base_index=2, description="", width=2, default_value=format(0, "02b") 

63 ) 

64 assert bit_vector.set_value(0b10) == 0b10_00 

65 

66 bit_vector = BitVector( 

67 name="", base_index=3, description="", width=4, default_value=format(0, "04b") 

68 ) 

69 assert bit_vector.set_value(0b1111) == 0b1111_000 

70 

71 bit_vector0 = BitVector(name="", base_index=0, description="", width=2, default_value="00") 

72 bit_vector1 = BitVector(name="", base_index=2, description="", width=4, default_value="0000") 

73 bit_vector2 = BitVector(name="", base_index=6, description="", width=3, default_value="000") 

74 

75 register_value = int("111000011", base=2) 

76 value0 = bit_vector0.set_value(bit_vector0.get_value(register_value)) 

77 value1 = bit_vector1.set_value(bit_vector1.get_value(register_value)) 

78 value2 = bit_vector2.set_value(bit_vector2.get_value(register_value)) 

79 assert value0 | value1 | value2 == register_value 

80 

81 register_value = int("000111100", base=2) 

82 value0 = bit_vector0.set_value(bit_vector0.get_value(register_value)) 

83 value1 = bit_vector1.set_value(bit_vector1.get_value(register_value)) 

84 value2 = bit_vector2.set_value(bit_vector2.get_value(register_value)) 

85 assert value0 | value1 | value2 == register_value 

86 

87 register_value = int("101010101", base=2) 

88 value0 = bit_vector0.set_value(bit_vector0.get_value(register_value)) 

89 value1 = bit_vector1.set_value(bit_vector1.get_value(register_value)) 

90 value2 = bit_vector2.set_value(bit_vector2.get_value(register_value)) 

91 assert value0 | value1 | value2 == register_value 

92 

93 # Test numerical_interpretation 

94 field = BitVector( 

95 name="", 

96 base_index=2, 

97 description="", 

98 width=16, 

99 default_value="0" * 16, 

100 numerical_interpretation=SignedFixedPoint.from_bit_widths( 

101 integer_bit_width=8, fraction_bit_width=8 

102 ), 

103 ) 

104 assert field.set_value(-0.00390625) == 0b11_11111111_11111100 

105 

106 

107def test_min_and_max_value(): 

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

109 assert bit_vector.numerical_interpretation.min_value == 0 

110 assert bit_vector.numerical_interpretation.max_value == 15 

111 

112 bit_vector = BitVector( 

113 name="", 

114 base_index=0, 

115 description="", 

116 width=4, 

117 default_value="0000", 

118 numerical_interpretation=Signed(bit_width=4), 

119 ) 

120 assert bit_vector.numerical_interpretation.min_value == -8 

121 assert bit_vector.numerical_interpretation.max_value == 7 

122 

123 bit_vector = BitVector( 

124 name="", 

125 base_index=0, 

126 description="", 

127 width=4, 

128 default_value="0000", 

129 numerical_interpretation=UnsignedFixedPoint(1, -2), 

130 ) 

131 assert bit_vector.numerical_interpretation.min_value == 0 

132 assert bit_vector.numerical_interpretation.max_value == 3.75 

133 

134 bit_vector = BitVector( 

135 name="", 

136 base_index=0, 

137 description="", 

138 width=4, 

139 default_value="0000", 

140 numerical_interpretation=SignedFixedPoint(1, -2), 

141 ) 

142 assert bit_vector.numerical_interpretation.min_value == -2 

143 assert bit_vector.numerical_interpretation.max_value == 1.75 

144 

145 

146def test_repr(): 

147 # Check that repr is an actual representation, not just "X object at 0xABCDEF" 

148 assert "apa" in repr( 

149 BitVector(name="apa", base_index=0, description="", width=1, default_value="0") 

150 ) 

151 

152 # Different name 

153 assert repr( 

154 BitVector(name="apa", base_index=0, description="", width=1, default_value="0") 

155 ) != repr(BitVector(name="hest", base_index=0, description="", width=1, default_value="0")) 

156 

157 # Different base_index 

158 assert repr( 

159 BitVector(name="apa", base_index=0, description="", width=1, default_value="0") 

160 ) != repr(BitVector(name="apa", base_index=1, description="", width=1, default_value="0")) 

161 

162 # Different description 

163 assert repr( 

164 BitVector(name="apa", base_index=0, description="Blah", width=1, default_value="0") 

165 ) != repr(BitVector(name="apa", base_index=0, description="Gaah", width=1, default_value="0")) 

166 

167 # Different width 

168 assert repr( 

169 BitVector(name="apa", base_index=0, description="", width=1, default_value="1") 

170 ) != repr(BitVector(name="apa", base_index=0, description="", width=2, default_value="11")) 

171 

172 # Different default_value 

173 assert repr( 

174 BitVector(name="apa", base_index=0, description="", width=1, default_value="1") 

175 ) != repr(BitVector(name="apa", base_index=0, description="", width=1, default_value="0")) 

176 

177 # Different numerical_interpretation 

178 field0 = BitVector( 

179 name="apa", 

180 base_index=0, 

181 description="", 

182 width=10, 

183 default_value="0" * 10, 

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

185 ) 

186 field1 = BitVector( 

187 name="apa", 

188 base_index=0, 

189 description="", 

190 width=10, 

191 default_value="0" * 10, 

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

193 ) 

194 field2 = BitVector( 

195 name="apa", 

196 base_index=0, 

197 description="", 

198 width=10, 

199 default_value="0" * 10, 

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

201 ) 

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

203 

204 

205def test_invalid_width(): 

206 with pytest.raises(ValueError) as exception_info: 

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

208 assert ( 

209 str(exception_info.value) 

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

211 ) 

212 

213 with pytest.raises(ValueError) as exception_info: 

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

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

216 

217 with pytest.raises(ValueError) as exception_info: 

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

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

220 

221 

222def test_invalid_default_value_should_raise_exception(): 

223 with pytest.raises(ValueError) as exception_info: 

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

225 assert str(exception_info.value) == ( 

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

227 ) 

228 

229 with pytest.raises(ValueError) as exception_info: 

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

231 assert str(exception_info.value) == ( 

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

233 ) 

234 

235 with pytest.raises(ValueError) as exception_info: 

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

237 assert str(exception_info.value) == ( 

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

239 ) 

240 

241 

242def test_can_update_default_value(): 

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

244 assert bit_vector.default_value == "1111" 

245 

246 bit_vector.default_value = "0000" 

247 assert bit_vector.default_value == "0000" 

248 

249 

250def test_updating_to_invalid_default_value_should_raise_exception(): 

251 # Create with a valid default_value 

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

253 

254 # Update to an invalid value 

255 with pytest.raises(ValueError) as exception_info: 

256 bit_vector.default_value = 1111 

257 assert str(exception_info.value) == ( 

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

259 ) 

260 

261 

262def test_default_value_uint(): 

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

264 assert bit_vector.default_value_uint == 0 

265 

266 bit_vector.default_value = "0010" 

267 assert bit_vector.default_value_uint == 2 

268 

269 bit_vector.default_value = "1001" 

270 assert bit_vector.default_value_uint == 9 

271 

272 

273def test_numeric_interpretation(): 

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

275 assert isinstance(bit_vector.numerical_interpretation, Unsigned) 

276 assert bit_vector.numerical_interpretation.bit_width == 4 

277 

278 numerical_interpretation = Signed(bit_width=10) 

279 bit_vector = BitVector( 

280 name="", 

281 base_index=0, 

282 description="", 

283 width=10, 

284 default_value="1111111111", 

285 numerical_interpretation=numerical_interpretation, 

286 ) 

287 assert bit_vector.numerical_interpretation is numerical_interpretation 

288 

289 

290def test_invalid_numerical_interpretation_width_should_raise_exception(): 

291 def test(numerical_interpretation): 

292 with pytest.raises(ValueError) as exception_info: 

293 BitVector( 

294 name="apa", 

295 base_index=0, 

296 description="", 

297 width=4, 

298 default_value="1111", 

299 numerical_interpretation=numerical_interpretation, 

300 ) 

301 

302 bit_width = ( 

303 numerical_interpretation.integer_bit_width + numerical_interpretation.fraction_bit_width 

304 ) 

305 expected = ( 

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

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

308 ) 

309 assert str(exception_info.value) == expected 

310 

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

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

313 

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

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