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

82 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 

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_unknown_top_level_property_should_raise_exception(tmp_path): 

18 toml_path = create_file( 

19 file=tmp_path / "regs.toml", 

20 contents=""" 

21mode = "w" 

22""", 

23 ) 

24 

25 with pytest.raises(ValueError) as exception_info: 

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

27 assert str(exception_info.value) == ( 

28 f'Error while parsing {toml_path}: Got unknown top-level property "mode".' 

29 ) 

30 

31 

32def test_unknown_top_level_item_type_should_raise_exception(tmp_path): 

33 toml_path = create_file( 

34 file=tmp_path / "regs.toml", 

35 contents=""" 

36hest.type = "register_constant" 

37""", 

38 ) 

39 

40 with pytest.raises(ValueError) as exception_info: 

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

42 assert str(exception_info.value) == ( 

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

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

45 ) 

46 

47 

48def test_order_of_registers_and_fields(tmp_path): # noqa: PLR0915 

49 toml_data = """ 

50################################################################################ 

51[data] 

52 

53type = "register" 

54mode = "w" 

55 

56 

57################################################################################ 

58[status] 

59 

60type = "register" 

61mode = "r_w" 

62description = "Status register" 

63 

64direction.type = "enumeration" 

65direction.description = "The direction mode" 

66direction.default_value = "input" 

67direction.element.passthrough = "" 

68direction.element.input = "" 

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

70 

71bad.type = "bit" 

72bad.description = "Bad things happen" 

73 

74interrupts.type = "bit_vector" 

75interrupts.width = 4 

76interrupts.description = "Many interrupts" 

77interrupts.default_value = "0110" 

78 

79not_good.type = "bit" 

80not_good.description = "" 

81not_good.default_value = "1" 

82 

83count.type = "integer" 

84count.description = "The number of things" 

85count.min_value = -5 

86count.max_value = 15 

87 

88 

89################################################################################ 

90[config] 

91 

92type = "register_array" 

93array_length = 3 

94description = "A register array" 

95 

96 

97# ------------------------------------------------------------------------------ 

98[config.input_settings] 

99 

100type = "register" 

101description = "Input configuration" 

102mode = "r_w" 

103 

104[config.input_settings.enable] 

105 

106type = "bit" 

107description = "Enable things" 

108default_value = "1" 

109 

110[config.input_settings.disable] 

111 

112type = "bit" 

113description = "" 

114default_value = "0" 

115 

116[config.input_settings.number] 

117 

118type = "integer" 

119description = "Configure number" 

120max_value = 3 

121default_value = 1 

122 

123[config.input_settings.size] 

124 

125type = "enumeration" 

126default_value = "large" 

127element.small = "" 

128element.medium = "" 

129element.large = "" 

130 

131 

132# ------------------------------------------------------------------------------ 

133[config.output_settings] 

134 

135type = "register" 

136mode = "w" 

137 

138[config.output_settings.data] 

139 

140type = "bit_vector" 

141width = 16 

142description = "Some data" 

143default_value = "0000000000000011" 

144""" 

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

146 

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

148 

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

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

151 assert registers[0].index == 0 

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

153 assert registers[0].default_value == 0 

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

155 

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

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

158 assert registers[1].index == 1 

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

160 

161 # Enumeration field 

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

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

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

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

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

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

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

169 

170 # Bit field 

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

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

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

174 

175 # Bit vector field 

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

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

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

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

180 

181 # Bit field 

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

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

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

185 

186 # Integer field 

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

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

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

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

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

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

193 

194 assert registers[1].default_value == ( 

195 # Enum 

196 1 * 2**0 

197 # Bit 

198 + 0 * 2**2 

199 # Bit vector 

200 + 6 * 2**3 

201 # Bit 

202 + 1 * 2**7 

203 # Integer, negative value converted to positive 

204 + 0b11011 * 2**8 

205 ) 

206 

207 assert registers[2].name == "config" 

208 assert registers[2].length == 3 

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

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

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

212 

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

228 assert registers[2].registers[0].default_value == ( 

229 # First bit 

230 1 * 2**0 

231 # Integer 

232 + 1 * 2**2 

233 # Enumeration 

234 + 2 * 2**4 

235 ) 

236 

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

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

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

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

241 assert registers[2].registers[1].default_value == 3 

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

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

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

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