Coverage for hdl_registers/parser/test/test_parser/test_parser.py: 100%

84 statements  

« prev     ^ index     » next       coverage.py v7.11.0, created at 2025-10-27 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 

10import pytest 

11from tsfpga.system_utils import create_file 

12 

13from hdl_registers.parser.toml import from_toml 

14from hdl_registers.register_modes import REGISTER_MODES 

15 

16 

17def test_property_names_and_values_are_case_sensitive(tmp_path): 

18 """ 

19 Explicitly show that we do not do any case normalization. 

20 """ 

21 toml_path = create_file( 

22 file=tmp_path / "regs.toml", 

23 contents=""" 

24[data] 

25 

26mode = "w" 

27""", 

28 ) 

29 from_toml(name="", toml_file=toml_path) 

30 

31 toml_path = create_file( 

32 file=tmp_path / "regs.toml", 

33 contents=""" 

34[data] 

35 

36Mode = "w" 

37""", 

38 ) 

39 with pytest.raises(ValueError) as exception_info: 

40 from_toml(name="", toml_file=toml_path) 

41 assert str(exception_info.value) == ( 

42 f'Error while parsing register "data" in {toml_path}: Missing required property "mode".' 

43 ) 

44 

45 toml_path = create_file( 

46 file=tmp_path / "regs.toml", 

47 contents=""" 

48[data] 

49 

50mode = "W" 

51""", 

52 ) 

53 with pytest.raises(ValueError) as exception_info: 

54 from_toml(name="", toml_file=toml_path) 

55 assert str(exception_info.value) == ( 

56 f'Error while parsing register "data" in {toml_path}: Got unknown mode "W". ' 

57 'Expected one of "r", "w", "r_w", "wpulse", "r_wpulse".' 

58 ) 

59 

60 

61def test_unknown_top_level_item_type_should_raise_exception(tmp_path): 

62 toml_path = create_file( 

63 file=tmp_path / "regs.toml", 

64 contents=""" 

65hest.type = "register_constant" 

66""", 

67 ) 

68 

69 with pytest.raises(ValueError) as exception_info: 

70 from_toml(name="", toml_file=toml_path) 

71 assert str(exception_info.value) == ( 

72 f'Error while parsing "hest" in {toml_path}: Got unknown type "register_constant". ' 

73 'Expected one of "constant", "register", "register_array".' 

74 ) 

75 

76 

77def test_order_of_registers_and_fields(tmp_path): # noqa: PLR0915 

78 toml_data = """ 

79################################################################################ 

80[data] 

81 

82type = "register" 

83mode = "w" 

84 

85 

86################################################################################ 

87[status] 

88 

89type = "register" 

90mode = "r_w" 

91description = "Status register" 

92 

93direction.type = "enumeration" 

94direction.description = "The direction mode" 

95direction.default_value = "input" 

96direction.element.passthrough = "" 

97direction.element.input = "" 

98direction.element.output = "use in output mode" 

99 

100bad.type = "bit" 

101bad.description = "Bad things happen" 

102 

103interrupts.type = "bit_vector" 

104interrupts.width = 4 

105interrupts.description = "Many interrupts" 

106interrupts.default_value = "0110" 

107 

108not_good.type = "bit" 

109not_good.description = "" 

110not_good.default_value = "1" 

111 

112count.type = "integer" 

113count.description = "The number of things" 

114count.min_value = -5 

115count.max_value = 15 

116 

117 

118################################################################################ 

119[conf] 

120 

121type = "register_array" 

122array_length = 3 

123description = "A register array" 

124 

125 

126# ------------------------------------------------------------------------------ 

127[conf.input_settings] 

128 

129type = "register" 

130description = "Input configuration" 

131mode = "r_w" 

132 

133[conf.input_settings.enable] 

134 

135type = "bit" 

136description = "Enable things" 

137default_value = "1" 

138 

139[conf.input_settings.disable] 

140 

141type = "bit" 

142description = "" 

143default_value = "0" 

144 

145[conf.input_settings.number] 

146 

147type = "integer" 

148description = "Configure number" 

149max_value = 3 

150default_value = 1 

151 

152[conf.input_settings.size] 

153 

154type = "enumeration" 

155default_value = "large" 

156element.small = "" 

157element.medium = "" 

158element.large = "" 

159 

160 

161# ------------------------------------------------------------------------------ 

162[conf.output_settings] 

163 

164type = "register" 

165mode = "w" 

166 

167[conf.output_settings.data] 

168 

169type = "bit_vector" 

170width = 16 

171description = "Some data" 

172default_value = "0000000000000011" 

173""" 

174 toml_file = create_file(file=tmp_path / "sensor_regs.toml", contents=toml_data) 

175 

176 registers = from_toml(name="sensor", toml_file=toml_file).register_objects 

177 

178 assert registers[0].name == "data" 

179 assert registers[0].mode == REGISTER_MODES["w"] 

180 assert registers[0].index == 0 

181 assert registers[0].description == "" 

182 assert registers[0].fields == [] 

183 

184 assert registers[1].name == "status" 

185 assert registers[1].mode == REGISTER_MODES["r_w"] 

186 assert registers[1].index == 1 

187 assert registers[1].description == "Status register" 

188 

189 # Enumeration field 

190 assert registers[1].fields[0].name == "direction" 

191 assert registers[1].fields[0].description == "The direction mode" 

192 assert registers[1].fields[0].width == 2 

193 assert registers[1].fields[0].default_value.name == "input" 

194 assert registers[1].fields[0].elements[0].name == "passthrough" 

195 assert registers[1].fields[0].elements[2].name == "output" 

196 assert registers[1].fields[0].elements[2].description == "use in output mode" 

197 

198 # Bit field 

199 assert registers[1].fields[1].name == "bad" 

200 assert registers[1].fields[1].description == "Bad things happen" 

201 assert registers[1].fields[1].default_value == "0" 

202 

203 # Bit vector field 

204 assert registers[1].fields[2].name == "interrupts" 

205 assert registers[1].fields[2].description == "Many interrupts" 

206 assert registers[1].fields[2].width == 4 

207 assert registers[1].fields[2].default_value == "0110" 

208 

209 # Bit field 

210 assert registers[1].fields[3].name == "not_good" 

211 assert registers[1].fields[3].description == "" 

212 assert registers[1].fields[3].default_value == "1" 

213 

214 # Integer field 

215 assert registers[1].fields[4].name == "count" 

216 assert registers[1].fields[4].description == "The number of things" 

217 assert registers[1].fields[4].width == 5 

218 assert registers[1].fields[4].min_value == -5 

219 assert registers[1].fields[4].max_value == 15 

220 assert registers[1].fields[4].default_value == -5 

221 

222 assert registers[2].name == "conf" 

223 assert registers[2].length == 3 

224 assert registers[2].description == "A register array" 

225 assert registers[2].index == 2 + 2 * 3 - 1 

226 assert len(registers[2].registers) == 2 

227 

228 assert registers[2].registers[0].name == "input_settings" 

229 assert registers[2].registers[0].mode == REGISTER_MODES["r_w"] 

230 assert registers[2].registers[0].index == 0 

231 assert registers[2].registers[0].description == "Input configuration" 

232 assert registers[2].registers[0].fields[0].name == "enable" 

233 assert registers[2].registers[0].fields[0].description == "Enable things" 

234 assert registers[2].registers[0].fields[0].default_value == "1" 

235 assert registers[2].registers[0].fields[1].name == "disable" 

236 assert registers[2].registers[0].fields[1].description == "" 

237 assert registers[2].registers[0].fields[1].default_value == "0" 

238 assert registers[2].registers[0].fields[2].name == "number" 

239 assert registers[2].registers[0].fields[2].description == "Configure number" 

240 assert registers[2].registers[0].fields[2].default_value == 1 

241 assert registers[2].registers[0].fields[3].name == "size" 

242 assert registers[2].registers[0].fields[3].default_value.name == "large" 

243 

244 assert registers[2].registers[1].name == "output_settings" 

245 assert registers[2].registers[1].mode == REGISTER_MODES["w"] 

246 assert registers[2].registers[1].index == 1 

247 assert registers[2].registers[1].description == "" 

248 assert registers[2].registers[1].fields[0].name == "data" 

249 assert registers[2].registers[1].fields[0].description == "Some data" 

250 assert registers[2].registers[1].fields[0].width == 16 

251 assert registers[2].registers[1].fields[0].default_value == "0000000000000011"