Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1# -------------------------------------------------------------------------------------------------- 

2# Copyright (c) Lukas Vik. All rights reserved. 

3# 

4# This file is part of the tsfpga project. 

5# https://tsfpga.com 

6# https://gitlab.com/tsfpga/tsfpga 

7# -------------------------------------------------------------------------------------------------- 

8 

9import unittest 

10import pytest 

11 

12from tsfpga.system_utils import create_file 

13from tsfpga.registers.parser import from_toml, load_toml_file 

14from tsfpga.registers.register import Register 

15 

16 

17def get_test_default_registers(): 

18 registers = [ 

19 Register("config", 0, "r_w", "Configuration register."), 

20 ] 

21 return registers 

22 

23 

24def test_bit_vector_without_width_should_raise_exception(tmp_path): 

25 toml_file = create_file( 

26 tmp_path / "regs.toml", 

27 """ 

28[register.test_reg] 

29 

30mode = "w" 

31 

32[register.test_reg.bit_vector.test_bit_vector] 

33 

34default_value = "0" 

35""", 

36 ) 

37 

38 with pytest.raises(ValueError) as exception_info: 

39 from_toml(module_name="", toml_file=toml_file) 

40 assert str(exception_info.value) == ( 

41 f'Bit vector "test_bit_vector" in register "test_reg" in file {toml_file} does not have ' 

42 'a "width" property' 

43 ) 

44 

45 

46# pylint: disable=too-many-public-methods 

47@pytest.mark.usefixtures("fixture_tmp_path") 

48class TestRegisterParser(unittest.TestCase): 

49 

50 tmp_path = None 

51 

52 module_name = "sensor" 

53 toml_data = """\ 

54 

55################################################################################ 

56[register.data] 

57 

58mode = "w" 

59 

60 

61################################################################################ 

62[register.irq] 

63 

64mode = "r_w" 

65description = "Interrupt register" 

66 

67[register.irq.bit.bad] 

68 

69description = "Bad things happen" 

70 

71[register.irq.bit.not_good] 

72 

73description = "" 

74default_value = "1" 

75 

76[register.irq.bit_vector.interrupts] 

77 

78width = 4 

79description = "Many interrupts" 

80default_value = "0110" 

81 

82 

83 

84################################################################################ 

85[register_array.configuration] 

86 

87array_length = 3 

88description = "A register array" 

89 

90# ------------------------------------------------------------------------------ 

91[register_array.configuration.register.input_settings] 

92 

93description = "Input configuration" 

94mode = "r_w" 

95 

96[register_array.configuration.register.input_settings.bit.enable] 

97 

98description = "Enable things" 

99default_value = "1" 

100 

101[register_array.configuration.register.input_settings.bit.disable] 

102 

103description = "" 

104default_value = "0" 

105 

106 

107# ------------------------------------------------------------------------------ 

108[register_array.configuration.register.output_settings] 

109 

110mode = "w" 

111 

112[register_array.configuration.register.output_settings.bit_vector.data] 

113 

114width=16 

115description = "Some data" 

116default_value="0000000000000011" 

117 

118 

119################################################################################ 

120""" 

121 

122 def setUp(self): 

123 self.toml_file = create_file(self.tmp_path / "sensor_regs.toml", self.toml_data) 

124 

125 def create_toml_file_with_extras(self, toml_extras): 

126 data = self.toml_data + toml_extras 

127 create_file(self.toml_file, data) 

128 

129 def test_order_of_registers_and_bits(self): 

130 registers = from_toml(self.module_name, self.toml_file).register_objects 

131 

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

133 assert registers[0].mode == "w" 

134 assert registers[0].index == 0 

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

136 assert registers[0].default_value == 0 

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

138 

139 assert registers[1].name == "irq" 

140 assert registers[1].mode == "r_w" 

141 assert registers[1].index == 1 

142 assert registers[1].description == "Interrupt register" 

143 assert registers[1].default_value == 6 * 2 ** 2 + 1 * 2 ** 1 

144 assert registers[1].fields[0].name == "bad" 

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

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

147 assert registers[1].fields[1].name == "not_good" 

148 assert registers[1].fields[1].description == "" 

149 assert registers[1].fields[1].default_value == "1" 

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

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

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

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

154 

155 assert registers[2].name == "configuration" 

156 assert registers[2].length == 3 

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

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

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

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

161 assert registers[2].registers[0].mode == "r_w" 

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

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

164 assert registers[2].registers[0].default_value == 1 

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

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

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

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

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

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

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

172 assert registers[2].registers[1].mode == "w" 

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

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

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

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

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

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

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

180 

181 def test_default_registers(self): 

182 default_registers = get_test_default_registers() 

183 num_default_registers = len(default_registers) 

184 toml_registers = from_toml(self.module_name, self.toml_file, default_registers) 

185 

186 # The registers from this test are appended at the end 

187 assert toml_registers.get_register("data").index == num_default_registers 

188 assert toml_registers.get_register("irq").index == num_default_registers + 1 

189 

190 def test_load_nonexistent_toml_file_should_raise_exception(self): 

191 file = self.toml_file.with_name("apa.toml") 

192 with pytest.raises(FileNotFoundError) as exception_info: 

193 load_toml_file(file) 

194 assert str(exception_info.value) == f"Requested TOML file does not exist: {file}" 

195 

196 def test_load_dirty_toml_file_should_raise_exception(self): 

197 self.create_toml_file_with_extras("apa") 

198 

199 with pytest.raises(ValueError) as exception_info: 

200 load_toml_file(self.toml_file) 

201 assert str(exception_info.value).startswith( 

202 f"Error while parsing TOML file {self.toml_file}:\nUnexpected character" 

203 ) 

204 

205 def test_plain_register_with_array_length_attribute_should_raise_exception(self): 

206 self.create_toml_file_with_extras( 

207 """ 

208[register.apa] 

209 

210mode = "r_w" 

211array_length = 4 

212""" 

213 ) 

214 

215 with pytest.raises(ValueError) as exception_info: 

216 from_toml(self.module_name, self.toml_file) 

217 assert ( 

218 str(exception_info.value) 

219 == f'Error while parsing register "apa" in {self.toml_file}: Unknown key "array_length"' 

220 ) 

221 

222 def test_register_array_but_no_array_length_attribute_should_raise_exception(self): 

223 self.create_toml_file_with_extras( 

224 """ 

225[register_array.apa] 

226 

227[register_array.apa.register.hest] 

228 

229mode = "r_w" 

230""" 

231 ) 

232 

233 with pytest.raises(ValueError) as exception_info: 

234 from_toml(self.module_name, self.toml_file) 

235 assert ( 

236 str(exception_info.value) 

237 == f'Register array "apa" in {self.toml_file} does not have "array_length" attribute' 

238 ) 

239 

240 def test_register_in_array_with_no_mode_attribute_should_raise_exception(self): 

241 self.create_toml_file_with_extras( 

242 """ 

243[register_array.apa] 

244 

245array_length = 2 

246 

247[register_array.apa.register.hest] 

248 

249description = "nothing" 

250""" 

251 ) 

252 

253 with pytest.raises(ValueError) as exception_info: 

254 from_toml(self.module_name, self.toml_file) 

255 assert ( 

256 str(exception_info.value) 

257 == f'Register "hest" within array "apa" in {self.toml_file} does not have "mode" field' 

258 ) 

259 

260 def test_register_with_no_mode_field_should_raise_exception(self): 

261 self.create_toml_file_with_extras( 

262 """ 

263[register.apa] 

264 

265description = "w" 

266""" 

267 ) 

268 

269 with pytest.raises(ValueError) as exception_info: 

270 from_toml(self.module_name, self.toml_file) 

271 assert ( 

272 str(exception_info.value) 

273 == f'Register "apa" in {self.toml_file} does not have "mode" field' 

274 ) 

275 

276 def test_two_registers_with_same_name_should_raise_exception(self): 

277 self.create_toml_file_with_extras( 

278 """ 

279[register.irq] 

280 

281mode = "w" 

282""" 

283 ) 

284 

285 with pytest.raises(ValueError) as exception_info: 

286 from_toml(self.module_name, self.toml_file) 

287 assert ( 

288 str(exception_info.value) 

289 == f'Error while parsing TOML file {self.toml_file}:\nKey "irq" already exists.' 

290 ) 

291 

292 def test_register_with_same_name_as_register_array_should_raise_exception(self): 

293 self.create_toml_file_with_extras( 

294 """ 

295[register.configuration] 

296 

297mode = "w" 

298""" 

299 ) 

300 

301 with pytest.raises(ValueError) as exception_info: 

302 from_toml(self.module_name, self.toml_file) 

303 assert str(exception_info.value) == f'Duplicate name "configuration" in {self.toml_file}' 

304 

305 def test_two_bits_with_same_name_should_raise_exception(self): 

306 self.create_toml_file_with_extras( 

307 """ 

308[register.test_reg] 

309 

310mode = "w" 

311 

312[register.test_reg.bit.test_bit] 

313 

314description = "Declaration 1" 

315 

316[register.test_reg.bit.test_bit] 

317 

318description = "Declaration 2" 

319""" 

320 ) 

321 

322 with pytest.raises(ValueError) as exception_info: 

323 from_toml(self.module_name, self.toml_file) 

324 assert ( 

325 str(exception_info.value) 

326 == f'Error while parsing TOML file {self.toml_file}:\nKey "test_bit" already exists.' 

327 ) 

328 

329 def test_overriding_default_register(self): 

330 self.create_toml_file_with_extras( 

331 """ 

332[register.config] 

333 

334description = "apa" 

335""" 

336 ) 

337 toml_registers = from_toml(self.module_name, self.toml_file, get_test_default_registers()) 

338 

339 assert toml_registers.get_register("config").description == "apa" 

340 

341 def test_changing_mode_of_default_register_should_raise_exception(self): 

342 self.create_toml_file_with_extras( 

343 """ 

344[register.config] 

345 

346mode = "w" 

347""" 

348 ) 

349 

350 with pytest.raises(ValueError) as exception_info: 

351 from_toml(self.module_name, self.toml_file, get_test_default_registers()) 

352 assert ( 

353 str(exception_info.value) 

354 == f'Overloading register "config" in {self.toml_file}, one can not change "mode" ' 

355 "from default" 

356 ) 

357 

358 def test_unknown_register_field_should_raise_exception(self): 

359 self.create_toml_file_with_extras( 

360 """ 

361[register.test_reg] 

362 

363mode = "w" 

364dummy = 3 

365""" 

366 ) 

367 

368 with pytest.raises(ValueError) as exception_info: 

369 from_toml(self.module_name, self.toml_file) 

370 assert ( 

371 str(exception_info.value) 

372 == f'Error while parsing register "test_reg" in {self.toml_file}: Unknown key "dummy"' 

373 ) 

374 

375 def test_unknown_register_array_field_should_raise_exception(self): 

376 self.create_toml_file_with_extras( 

377 """ 

378[register_array.test_array] 

379 

380array_length = 2 

381dummy = 3 

382 

383[register_array.test_array.hest] 

384 

385mode = "r" 

386""" 

387 ) 

388 

389 with pytest.raises(ValueError) as exception_info: 

390 from_toml(self.module_name, self.toml_file) 

391 assert ( 

392 str(exception_info.value) 

393 == f'Error while parsing register array "test_array" in {self.toml_file}: ' 

394 'Unknown key "dummy"' 

395 ) 

396 

397 def test_unknown_register_field_in_register_array_should_raise_exception(self): 

398 self.create_toml_file_with_extras( 

399 """ 

400[register_array.test_array] 

401 

402array_length = 2 

403 

404[register_array.test_array.register.hest] 

405 

406mode = "r" 

407dummy = 3 

408""" 

409 ) 

410 

411 with pytest.raises(ValueError) as exception_info: 

412 from_toml(self.module_name, self.toml_file) 

413 assert ( 

414 str(exception_info.value) 

415 == f'Error while parsing register "hest" in array "test_array" in {self.toml_file}: ' 

416 'Unknown key "dummy"' 

417 ) 

418 

419 def test_unknown_bit_field_should_raise_exception(self): 

420 self.create_toml_file_with_extras( 

421 """ 

422[register.dummy_reg] 

423 

424mode = "w" 

425 

426[register.dummy_reg.bit.dummy_bit] 

427 

428description = "Stuff" 

429height = 3 

430""" 

431 ) 

432 

433 with pytest.raises(ValueError) as exception_info: 

434 from_toml(self.module_name, self.toml_file) 

435 assert ( 

436 str(exception_info.value) 

437 == f'Error while parsing bit "dummy_bit" in register "dummy_reg" in {self.toml_file}: ' 

438 'Unknown key "height"' 

439 ) 

440 

441 def test_unknown_bit_vector_field_should_raise_exception(self): 

442 self.create_toml_file_with_extras( 

443 """ 

444[register.dummy_reg] 

445 

446mode = "w" 

447 

448[register.dummy_reg.bit_vector.dummy_bit_vector] 

449 

450description = "Stuff" 

451width = 3 

452height = 4 

453 

454""" 

455 ) 

456 

457 with pytest.raises(ValueError) as exception_info: 

458 from_toml(self.module_name, self.toml_file) 

459 assert ( 

460 str(exception_info.value) 

461 == f'Error while parsing bit vector "dummy_bit_vector" in register "dummy_reg" in ' 

462 f'{self.toml_file}: Unknown key "height"' 

463 ) 

464 

465 def test_constants_in_toml(self): 

466 self.create_toml_file_with_extras( 

467 """ 

468[constant.data_width] 

469 

470value = 0xf 

471description = "the width" 

472""" 

473 ) 

474 

475 register_list = from_toml(self.module_name, self.toml_file) 

476 assert len(register_list.constants) == 1 

477 assert register_list.constants[0].name == "data_width" 

478 assert register_list.constants[0].value == 15 

479 assert register_list.constants[0].description == "the width" 

480 

481 def test_unknown_constant_field_should_raise_exception(self): 

482 self.create_toml_file_with_extras( 

483 """ 

484[constant.data_width] 

485 

486value = 0xf 

487default_value = 0xf 

488""" 

489 ) 

490 

491 with pytest.raises(ValueError) as exception_info: 

492 from_toml(self.module_name, self.toml_file) 

493 assert ( 

494 str(exception_info.value) 

495 == f'Error while parsing constant "data_width" in {self.toml_file}: ' 

496 'Unknown key "default_value"' 

497 )