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%s 

121""" 

122 

123 def setUp(self): 

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

125 

126 def create_toml_file_with_extras(self, toml_extras): 

127 data = self.toml_data % toml_extras 

128 create_file(self.toml_file, data) 

129 

130 def test_order_of_registers_and_bits(self): 

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

132 

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

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

135 assert registers[0].index == 0 

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

137 assert registers[0].default_value == 0 

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

139 

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

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

142 assert registers[1].index == 1 

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

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

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

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

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

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

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

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

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

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

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

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

155 

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

157 assert registers[2].length == 3 

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

181 

182 def test_default_registers(self): 

183 default_registers = get_test_default_registers() 

184 num_default_registers = len(default_registers) 

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

186 

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

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

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

190 

191 def test_load_nonexistent_toml_file_should_raise_exception(self): 

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

193 with pytest.raises(FileNotFoundError) as exception_info: 

194 load_toml_file(file) 

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

196 

197 def test_load_dirty_toml_file_should_raise_exception(self): 

198 self.create_toml_file_with_extras("apa") 

199 

200 with pytest.raises(ValueError) as exception_info: 

201 load_toml_file(self.toml_file) 

202 assert str(exception_info.value).startswith( 

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

204 ) 

205 

206 def test_plain_register_with_array_length_attribute_should_raise_exception(self): 

207 self.create_toml_file_with_extras( 

208 """ 

209[register.apa] 

210 

211mode = "r_w" 

212array_length = 4 

213""" 

214 ) 

215 

216 with pytest.raises(ValueError) as exception_info: 

217 from_toml(self.module_name, self.toml_file) 

218 assert ( 

219 str(exception_info.value) 

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

221 ) 

222 

223 def test_register_array_but_no_array_length_attribute_should_raise_exception(self): 

224 self.create_toml_file_with_extras( 

225 """ 

226[register_array.apa] 

227 

228[register_array.apa.register.hest] 

229 

230mode = "r_w" 

231""" 

232 ) 

233 

234 with pytest.raises(ValueError) as exception_info: 

235 from_toml(self.module_name, self.toml_file) 

236 assert ( 

237 str(exception_info.value) 

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

239 ) 

240 

241 def test_register_in_array_with_no_mode_attribute_should_raise_exception(self): 

242 self.create_toml_file_with_extras( 

243 """ 

244[register_array.apa] 

245 

246array_length = 2 

247 

248[register_array.apa.register.hest] 

249 

250description = "nothing" 

251""" 

252 ) 

253 

254 with pytest.raises(ValueError) as exception_info: 

255 from_toml(self.module_name, self.toml_file) 

256 assert ( 

257 str(exception_info.value) 

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

259 ) 

260 

261 def test_register_with_no_mode_field_should_raise_exception(self): 

262 self.create_toml_file_with_extras( 

263 """ 

264[register.apa] 

265 

266description = "w" 

267""" 

268 ) 

269 

270 with pytest.raises(ValueError) as exception_info: 

271 from_toml(self.module_name, self.toml_file) 

272 assert ( 

273 str(exception_info.value) 

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

275 ) 

276 

277 def test_two_registers_with_same_name_should_raise_exception(self): 

278 self.create_toml_file_with_extras( 

279 """ 

280[register.irq] 

281 

282mode = "w" 

283""" 

284 ) 

285 

286 with pytest.raises(ValueError) as exception_info: 

287 from_toml(self.module_name, self.toml_file) 

288 assert ( 

289 str(exception_info.value) 

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

291 ) 

292 

293 def test_register_with_same_name_as_register_array_should_raise_exception(self): 

294 self.create_toml_file_with_extras( 

295 """ 

296[register.configuration] 

297 

298mode = "w" 

299""" 

300 ) 

301 

302 with pytest.raises(ValueError) as exception_info: 

303 from_toml(self.module_name, self.toml_file) 

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

305 

306 def test_two_bits_with_same_name_should_raise_exception(self): 

307 self.create_toml_file_with_extras( 

308 """ 

309[register.test_reg] 

310 

311mode = "w" 

312 

313[register.test_reg.bit.test_bit] 

314 

315description = "Declaration 1" 

316 

317[register.test_reg.bit.test_bit] 

318 

319description = "Declaration 2" 

320""" 

321 ) 

322 

323 with pytest.raises(ValueError) as exception_info: 

324 from_toml(self.module_name, self.toml_file) 

325 assert ( 

326 str(exception_info.value) 

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

328 ) 

329 

330 def test_overriding_default_register(self): 

331 self.create_toml_file_with_extras( 

332 """ 

333[register.config] 

334 

335description = "apa" 

336""" 

337 ) 

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

339 

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

341 

342 def test_changing_mode_of_default_register_should_raise_exception(self): 

343 self.create_toml_file_with_extras( 

344 """ 

345[register.config] 

346 

347mode = "w" 

348""" 

349 ) 

350 

351 with pytest.raises(ValueError) as exception_info: 

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

353 assert ( 

354 str(exception_info.value) 

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

356 "from default" 

357 ) 

358 

359 def test_unknown_register_field_should_raise_exception(self): 

360 self.create_toml_file_with_extras( 

361 """ 

362[register.test_reg] 

363 

364mode = "w" 

365dummy = 3 

366""" 

367 ) 

368 

369 with pytest.raises(ValueError) as exception_info: 

370 from_toml(self.module_name, self.toml_file) 

371 assert ( 

372 str(exception_info.value) 

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

374 ) 

375 

376 def test_unknown_register_array_field_should_raise_exception(self): 

377 self.create_toml_file_with_extras( 

378 """ 

379[register_array.test_array] 

380 

381array_length = 2 

382dummy = 3 

383 

384[register_array.test_array.hest] 

385 

386mode = "r" 

387""" 

388 ) 

389 

390 with pytest.raises(ValueError) as exception_info: 

391 from_toml(self.module_name, self.toml_file) 

392 assert ( 

393 str(exception_info.value) 

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

395 'Unknown key "dummy"' 

396 ) 

397 

398 def test_unknown_register_field_in_register_array_should_raise_exception(self): 

399 self.create_toml_file_with_extras( 

400 """ 

401[register_array.test_array] 

402 

403array_length = 2 

404 

405[register_array.test_array.register.hest] 

406 

407mode = "r" 

408dummy = 3 

409""" 

410 ) 

411 

412 with pytest.raises(ValueError) as exception_info: 

413 from_toml(self.module_name, self.toml_file) 

414 assert ( 

415 str(exception_info.value) 

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

417 'Unknown key "dummy"' 

418 ) 

419 

420 def test_unknown_bit_field_should_raise_exception(self): 

421 self.create_toml_file_with_extras( 

422 """ 

423[register.dummy_reg] 

424 

425mode = "w" 

426 

427[register.dummy_reg.bit.dummy_bit] 

428 

429description = "Stuff" 

430height = 3 

431""" 

432 ) 

433 

434 with pytest.raises(ValueError) as exception_info: 

435 from_toml(self.module_name, self.toml_file) 

436 assert ( 

437 str(exception_info.value) 

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

439 'Unknown key "height"' 

440 ) 

441 

442 def test_unknown_bit_vector_field_should_raise_exception(self): 

443 self.create_toml_file_with_extras( 

444 """ 

445[register.dummy_reg] 

446 

447mode = "w" 

448 

449[register.dummy_reg.bit_vector.dummy_bit_vector] 

450 

451description = "Stuff" 

452width = 3 

453height = 4 

454 

455""" 

456 ) 

457 

458 with pytest.raises(ValueError) as exception_info: 

459 from_toml(self.module_name, self.toml_file) 

460 assert ( 

461 str(exception_info.value) 

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

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

464 ) 

465 

466 def test_constants_in_toml(self): 

467 self.create_toml_file_with_extras( 

468 """ 

469[constant.data_width] 

470 

471value = 0xf 

472description = "the width" 

473""" 

474 ) 

475 

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

477 assert len(register_list.constants) == 1 

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

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

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

481 

482 def test_unknown_constant_field_should_raise_exception(self): 

483 self.create_toml_file_with_extras( 

484 """ 

485[constant.data_width] 

486 

487value = 0xf 

488default_value = 0xf 

489""" 

490 ) 

491 

492 with pytest.raises(ValueError) as exception_info: 

493 from_toml(self.module_name, self.toml_file) 

494 assert ( 

495 str(exception_info.value) 

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

497 'Unknown key "default_value"' 

498 )