Coverage for hdl_registers/generator/systemverilog/axi_lite/test/test_register_file.py: 100%

136 statements  

« prev     ^ index     » next       coverage.py v7.8.0, created at 2025-04-29 06:41 +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, read_file 

12 

13from hdl_registers.field.enumeration import Enumeration 

14from hdl_registers.field.integer import Integer 

15from hdl_registers.field.numerical_interpretation import ( 

16 Signed, 

17 SignedFixedPoint, 

18 UnsignedFixedPoint, 

19) 

20from hdl_registers.generator.systemverilog.axi_lite.register_file import ( 

21 SystemVerilogAxiLiteGenerator, 

22) 

23from hdl_registers.register_list import RegisterList 

24from hdl_registers.register_modes import REGISTER_MODES 

25 

26 

27def get_basic_register_list(path=None): 

28 source_definition_file = None if path is None else path 

29 register_list = RegisterList(name="caesar", source_definition_file=source_definition_file) 

30 

31 register = register_list.append_register(name="reg0", mode=REGISTER_MODES["w"], description="") 

32 register.append_bit(name="bit0", description="", default_value="0") 

33 register.append_bit(name="bit1", description="", default_value="1") 

34 register.append_bit_vector(name="bit_vector0", description="", width=4, default_value="1101") 

35 register.append_bit_vector( 

36 name="bit_vector1", 

37 description="", 

38 width=4, 

39 default_value="1001", 

40 numerical_interpretation=Signed(bit_width=4), 

41 ) 

42 register.append_bit_vector( 

43 name="bit_vector2", 

44 description="", 

45 width=4, 

46 default_value="1101", 

47 numerical_interpretation=UnsignedFixedPoint(1, -2), 

48 ) 

49 register.append_bit_vector( 

50 name="bit_vector3", 

51 description="", 

52 width=4, 

53 default_value="1101", 

54 numerical_interpretation=SignedFixedPoint(2, -1), 

55 ) 

56 register.append_integer( 

57 name="int0", min_value=3, max_value=16383, default_value=16377, description="" 

58 ) 

59 

60 register = register_list.append_register(name="reg1", mode=REGISTER_MODES["r"], description="") 

61 register.append_enumeration( 

62 name="enum0", 

63 description="", 

64 elements={"element0": "", "element1": "", "element2": "", "element3": "", "element4": ""}, 

65 default_value="element1", 

66 ) 

67 register.append_bit_vector(name="bit_vector4", description="", width=1, default_value="0") 

68 register.append_bit(name="bit2", description="", default_value="1") 

69 

70 register = register_list.append_register( 

71 name="reg2", mode=REGISTER_MODES["r_w"], description="" 

72 ) 

73 register.append_bit_vector(name="bit_vector5", description="", width=6, default_value="010101") 

74 register.append_enumeration( 

75 name="enum1", description="", elements={"element5": ""}, default_value="element5" 

76 ) 

77 

78 return register_list 

79 

80 

81def test_basic_register_list(tmp_path): 

82 generator = SystemVerilogAxiLiteGenerator( 

83 register_list=get_basic_register_list(), output_folder=tmp_path 

84 ) 

85 generator.create() 

86 

87 for generated_file in generator.output_files: 

88 print(generated_file) 

89 

90 

91def test_create_if_needed(tmp_path): 

92 generator = SystemVerilogAxiLiteGenerator( 

93 register_list=get_basic_register_list(), output_folder=tmp_path 

94 ) 

95 

96 def create(expect_create: bool = True): 

97 created, _ = generator.create_if_needed() 

98 assert created == expect_create 

99 

100 create() 

101 create(expect_create=False) 

102 

103 sv = read_file(generator.output_file) 

104 create_file(generator.output_file, sv.replace("hdl-registers version ", "AAAAAAA")) 

105 create() 

106 create(expect_create=False) 

107 

108 (tmp_path / "caesar_register_file_axi_lite.sv").unlink() 

109 create() 

110 create(expect_create=False) 

111 

112 (tmp_path / "caesar_register_file_axi_lite_pkg.sv").unlink() 

113 create() 

114 create(expect_create=False) 

115 

116 

117def test_flatten(tmp_path): 

118 generator = SystemVerilogAxiLiteGenerator( 

119 register_list=get_basic_register_list(), output_folder=tmp_path 

120 ) 

121 

122 interface = "axi4lite_intf.slave s_axil," 

123 flattened = "input wire s_axil_awvalid," 

124 

125 generator.create(flatten_axi_lite=True) 

126 sv = read_file(generator.output_file) 

127 

128 assert interface not in sv 

129 assert flattened in sv 

130 

131 generator.create(flatten_axi_lite=False) 

132 sv = read_file(generator.output_file) 

133 

134 assert interface in sv 

135 assert flattened not in sv 

136 

137 

138def test_with_and_without_source_definition_file(tmp_path): 

139 """ 

140 The name of the source definition file does not seem to appear anywhere in the 

141 generated SystemVerilog code. 

142 But we set it anyway since it's part of the API. 

143 In SystemRDL it is required, but in hdl-registers it is optional, so we test both cases. 

144 """ 

145 SystemVerilogAxiLiteGenerator( 

146 register_list=get_basic_register_list(path=tmp_path), output_folder=tmp_path 

147 ).create() 

148 SystemVerilogAxiLiteGenerator( 

149 register_list=get_basic_register_list(), output_folder=tmp_path 

150 ).create() 

151 

152 

153def test_default_values_on_reset(tmp_path): 

154 register_list = get_basic_register_list() 

155 sv = read_file( 

156 SystemVerilogAxiLiteGenerator(register_list=register_list, output_folder=tmp_path).create() 

157 ) 

158 

159 for register in register_list.register_objects: 

160 for field in register.fields: 

161 default_value_int = ( 

162 field.default_value.value 

163 if isinstance(field, Enumeration) 

164 else field.default_value 

165 if isinstance(field, Integer) 

166 else int(field.default_value, 2) 

167 ) 

168 default_value_hex = hex(default_value_int)[2:] 

169 

170 print(field) 

171 reset_assign = f""" 

172 if(rst) begin 

173 field_storage.{register.name}.{field.name}.value <=""" 

174 

175 if register.mode.software_can_write: 

176 assert f"{reset_assign} {field.width}'h{default_value_hex};\n" in sv 

177 else: 

178 assert reset_assign not in sv 

179 

180 

181def test_field_bit_indexes(tmp_path): 

182 register_list = get_basic_register_list(path=tmp_path) 

183 sv = read_file( 

184 SystemVerilogAxiLiteGenerator(register_list=register_list, output_folder=tmp_path).create() 

185 ) 

186 

187 for register in register_list.register_objects: 

188 for field in register.fields: 

189 bits = f"{field.base_index + field.width - 1}:{field.base_index}" 

190 

191 if register.mode.software_can_write: 

192 assert ( 

193 f"next_c = " 

194 f"(field_storage.{register.name}.{field.name}.value " 

195 f"& ~decoded_wr_biten[{bits}])" 

196 ) in sv 

197 

198 if register.mode.software_can_read: 

199 value_source = "field_storage" if register.mode.software_can_write else "hwif_in" 

200 assert ( 

201 f"[{bits}] = (decoded_reg_strb.{register.name} && !decoded_req_is_wr) ? " 

202 f"{value_source}.{register.name}.{field.name}." 

203 ) in sv 

204 

205 

206def test_enumeration_naming_and_encoding(tmp_path): 

207 SystemVerilogAxiLiteGenerator( 

208 register_list=get_basic_register_list(path=tmp_path), output_folder=tmp_path 

209 ).create() 

210 sv = read_file(tmp_path / "caesar_register_file_axi_lite_pkg.sv") 

211 

212 assert ( 

213 """ 

214 typedef enum logic [2:0] { 

215 caesar_reg1_enum0__element0 = 'h0, 

216 caesar_reg1_enum0__element1 = 'h1, 

217 caesar_reg1_enum0__element2 = 'h2, 

218 caesar_reg1_enum0__element3 = 'h3, 

219 caesar_reg1_enum0__element4 = 'h4 

220 } caesar_reg1_enum0_e; 

221 

222 typedef enum logic { 

223 caesar_reg2_enum1__element5 = 'h0 

224 } caesar_reg2_enum1_e; 

225""" 

226 in sv 

227 ) 

228 

229 

230def test_empty_register_list(tmp_path): 

231 register_list = RegisterList(name="empty") 

232 _test_empty_register_list(register_list=register_list, tmp_path=tmp_path) 

233 

234 

235def _test_empty_register_list(register_list, tmp_path, extra=""): 

236 with pytest.raises(ValueError) as exception_info: 

237 SystemVerilogAxiLiteGenerator(register_list=register_list, output_folder=tmp_path).create() 

238 assert str(exception_info.value) == ( 

239 f'Error while translating "empty"{extra}: ' 

240 "SystemVerilog generator requires at least one register." 

241 ) 

242 

243 

244def test_error_message_with_and_without_source_definition_file(tmp_path): 

245 register_list = RegisterList(name="empty") 

246 _test_empty_register_list(register_list=register_list, tmp_path=tmp_path) 

247 

248 register_list = RegisterList(name="empty", source_definition_file=tmp_path) 

249 _test_empty_register_list( 

250 register_list=register_list, tmp_path=tmp_path, extra=f" in {tmp_path}" 

251 ) 

252 

253 

254def test_register_array(tmp_path): 

255 register_list = get_basic_register_list(path=tmp_path) 

256 register_list.append_register_array(name="a", length=2, description="").append_register( 

257 "b", mode=REGISTER_MODES["r"], description="" 

258 ) 

259 

260 with pytest.raises(ValueError) as exception_info: 

261 SystemVerilogAxiLiteGenerator(register_list=register_list, output_folder=tmp_path).create() 

262 assert str(exception_info.value) == ( 

263 f'Error while translating "caesar.a" in {tmp_path}: ' 

264 "SystemVerilog generator does not support register arrays." 

265 ) 

266 

267 

268def test_empty_register(tmp_path): 

269 register_list = get_basic_register_list(path=tmp_path) 

270 register_list.append_register("b", mode=REGISTER_MODES["r"], description="") 

271 

272 with pytest.raises(ValueError) as exception_info: 

273 SystemVerilogAxiLiteGenerator(register_list=register_list, output_folder=tmp_path).create() 

274 assert str(exception_info.value) == ( 

275 f'Error while translating "caesar.b" in {tmp_path}: ' 

276 "SystemVerilog generator requires at least one field per register." 

277 ) 

278 

279 

280def test_signed_integer_field(tmp_path): 

281 register_list = get_basic_register_list(path=tmp_path) 

282 register_list.append_register("b", mode=REGISTER_MODES["r"], description="").append_integer( 

283 name="c", min_value=-1, max_value=1, default_value=0, description="" 

284 ) 

285 

286 with pytest.raises(ValueError) as exception_info: 

287 SystemVerilogAxiLiteGenerator(register_list=register_list, output_folder=tmp_path).create() 

288 assert str(exception_info.value) == ( 

289 f'Error while translating "caesar.b.c" in {tmp_path}: ' 

290 "SystemVerilog generator does not support signed integer fields." 

291 ) 

292 

293 

294def test_constant(tmp_path): 

295 register_list = get_basic_register_list(path=tmp_path) 

296 register_list.add_constant(name="c", value=42, description="") 

297 

298 with pytest.raises(ValueError) as exception_info: 

299 SystemVerilogAxiLiteGenerator(register_list=register_list, output_folder=tmp_path).create() 

300 assert str(exception_info.value) == ( 

301 f'Error while translating "caesar" in {tmp_path}: ' 

302 "SystemVerilog generator does not support constants." 

303 ) 

304 

305 

306def test_register_mode_r_wpulse(tmp_path): 

307 def run_test(mode): 

308 register_list = get_basic_register_list(path=tmp_path) 

309 register_list.append_register( 

310 name="a", mode=REGISTER_MODES[mode], description="" 

311 ).append_bit(name="b", description="", default_value="1") 

312 

313 with pytest.raises(ValueError) as exception_info: 

314 SystemVerilogAxiLiteGenerator( 

315 register_list=register_list, output_folder=tmp_path 

316 ).create() 

317 assert str(exception_info.value) == ( 

318 f'Error while translating "caesar.a" in {tmp_path}: ' 

319 "SystemVerilog generator does not support " 

320 f"register mode: RegisterMode(shorthand={mode})" 

321 ) 

322 

323 run_test("r_wpulse") 

324 run_test("wpulse")