Coverage for hdl_registers/generator/vhdl/test/test_register_vhdl_generator.py: 100%

96 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 

10""" 

11Some limited unit tests that check the generated code. 

12Note that the generated VHDL code is also simulated in a functional test. 

13""" 

14 

15from pathlib import Path 

16 

17from tsfpga.system_utils import read_file 

18 

19from hdl_registers import HDL_REGISTERS_DOC 

20from hdl_registers.generator.vhdl.axi_lite.wrapper import VhdlAxiLiteWrapperGenerator 

21from hdl_registers.generator.vhdl.record_package import VhdlRecordPackageGenerator 

22from hdl_registers.generator.vhdl.register_package import VhdlRegisterPackageGenerator 

23from hdl_registers.generator.vhdl.simulation.check_package import ( 

24 VhdlSimulationCheckPackageGenerator, 

25) 

26from hdl_registers.generator.vhdl.simulation.read_write_package import ( 

27 VhdlSimulationReadWritePackageGenerator, 

28) 

29from hdl_registers.generator.vhdl.simulation.wait_until_package import ( 

30 VhdlSimulationWaitUntilPackageGenerator, 

31) 

32from hdl_registers.parser.toml import from_toml 

33from hdl_registers.register_list import RegisterList 

34from hdl_registers.register_modes import REGISTER_MODES 

35 

36 

37def generate_all_vhdl_artifacts(register_list: RegisterList, output_folder: Path) -> None: 

38 VhdlRegisterPackageGenerator( 

39 register_list=register_list, output_folder=output_folder 

40 ).create_if_needed() 

41 

42 VhdlRecordPackageGenerator( 

43 register_list=register_list, output_folder=output_folder 

44 ).create_if_needed() 

45 

46 VhdlAxiLiteWrapperGenerator( 

47 register_list=register_list, output_folder=output_folder 

48 ).create_if_needed() 

49 

50 VhdlSimulationReadWritePackageGenerator( 

51 register_list=register_list, output_folder=output_folder 

52 ).create_if_needed() 

53 

54 VhdlSimulationCheckPackageGenerator( 

55 register_list=register_list, output_folder=output_folder 

56 ).create_if_needed() 

57 

58 VhdlSimulationWaitUntilPackageGenerator( 

59 register_list=register_list, output_folder=output_folder 

60 ).create_if_needed() 

61 

62 

63def get_strange_register_lists() -> list[RegisterList]: 

64 """ 

65 Create some strange register lists for testing of niche cases. 

66 """ 

67 result = [] 

68 

69 def create_packages(direction, mode): 

70 def append_register(data, name): 

71 """ 

72 Append a register with some fields. 

73 """ 

74 register = data.append_register( 

75 name=f"{name}_{mode.shorthand}", mode=mode, description="" 

76 ) 

77 

78 register.append_integer( 

79 name="integer", description="", min_value=-10, max_value=10, default_value=3 

80 ) 

81 register.append_enumeration( 

82 name="enumeration", description="", elements={"a": "", "b": ""}, default_value="b" 

83 ) 

84 

85 def append_registers(data): 

86 """ 

87 Append some registers with some fields, either to a RegisterList or a RegisterArray. 

88 """ 

89 append_register(data=data, name="first") 

90 append_register(data=data, name="second") 

91 

92 # Some plain registers, in one direction only. 

93 register_list = RegisterList(name=f"plain_only_{direction}") 

94 append_registers(data=register_list) 

95 result.append(register_list) 

96 

97 # Some register arrays, in one direction only. 

98 register_list = RegisterList(name=f"array_only_{direction}") 

99 register_array = register_list.append_register_array(name="apa", length=5, description="") 

100 append_registers(data=register_array) 

101 register_array = register_list.append_register_array(name="hest", length=10, description="") 

102 append_registers(data=register_array) 

103 result.append(register_list) 

104 

105 # Plain registers and some register arrays, in one direction only. 

106 register_list = RegisterList(name=f"plain_and_array_only_{direction}") 

107 append_registers(data=register_list) 

108 register_array = register_list.append_register_array(name="apa", length=5, description="") 

109 append_registers(data=register_array) 

110 register_array = register_list.append_register_array(name="hest", length=10, description="") 

111 append_registers(data=register_array) 

112 result.append(register_list) 

113 

114 # Mode 'Read only' should give registers only in the 'up' direction' 

115 create_packages(direction="up", mode=REGISTER_MODES["r"]) 

116 # Mode 'Write only' should give registers only in the 'down' direction' 

117 create_packages(direction="down", mode=REGISTER_MODES["w"]) 

118 

119 register_list = RegisterList(name="only_constants") 

120 register_list.add_constant(name="first", value=123, description="") 

121 register_list.add_constant(name="second", value=True, description="") 

122 register_list.add_constant(name="third", value=5e30, description="") 

123 register_list.add_constant(name="fourth", value=1e-12, description="") 

124 result.append(register_list) 

125 

126 result.append(RegisterList(name="empty")) 

127 

128 return result 

129 

130 

131def get_all_doc_register_lists() -> list[RegisterList]: 

132 """ 

133 Get all register lists that are used for documentation. 

134 """ 

135 return [ 

136 from_toml(name=toml_file.stem, toml_file=toml_file) 

137 for toml_file in HDL_REGISTERS_DOC.glob("**/*.toml") 

138 if "default_registers" not in toml_file.stem 

139 ] 

140 

141 

142def generate_strange_register_maps(output_path): 

143 """ 

144 Generate register VHDL artifacts for some strange niche cases. 

145 """ 

146 for register_list in get_strange_register_lists(): 

147 generate_all_vhdl_artifacts(register_list=register_list, output_folder=output_path) 

148 

149 

150def _get_register_arrays_record_string(direction): 

151 return ( 

152 f"records for the registers of each register array the are in the '{direction}' direction" 

153 ) 

154 

155 

156def test_registers_only_in_up_direction_should_give_no_down_type_or_port(tmp_path): 

157 generate_strange_register_maps(output_path=tmp_path) 

158 

159 for file_name in ["array_only_up", "plain_and_array_only_up", "plain_only_up"]: 

160 vhd = read_file(tmp_path / f"{file_name}_register_record_pkg.vhd") 

161 

162 assert f"{file_name}_regs_up_t" in vhd 

163 assert f"{file_name}_regs_down_t" not in vhd 

164 

165 # If there are no arrays there should be no records for arrays, and this comment shall not 

166 # be present. 

167 string = _get_register_arrays_record_string("up") 

168 if "array" in file_name: 

169 assert string in vhd 

170 else: 

171 assert string not in vhd 

172 

173 # The 'down' comment shall never be present since we have no 'down' registers. 

174 string = _get_register_arrays_record_string("down") 

175 assert string not in vhd 

176 

177 vhd = read_file(tmp_path / f"{file_name}_register_file_axi_lite.vhd") 

178 

179 assert "regs_up : in" in vhd 

180 assert "regs_down : out" not in vhd 

181 

182 assert "reg_was_read : out" in vhd 

183 assert "reg_was_written : out" not in vhd 

184 

185 

186def test_registers_only_in_down_direction_should_give_no_down_type_or_port(tmp_path): 

187 generate_strange_register_maps(output_path=tmp_path) 

188 

189 for file_name in ["array_only_down", "plain_and_array_only_down", "plain_only_down"]: 

190 vhd = read_file(tmp_path / f"{file_name}_register_record_pkg.vhd") 

191 

192 assert f"{file_name}_regs_up_t" not in vhd 

193 assert f"{file_name}_regs_down_t" in vhd 

194 

195 # If there are no arrays there should be no records for arrays, and this comment shall not 

196 # be present. 

197 string = _get_register_arrays_record_string("down") 

198 if "array" in file_name: 

199 assert string in vhd 

200 else: 

201 assert string not in vhd 

202 

203 # The 'up' comment shall never be present since we have no 'up' registers. 

204 string = _get_register_arrays_record_string("up") 

205 assert string not in vhd 

206 

207 vhd = read_file(tmp_path / f"{file_name}_register_file_axi_lite.vhd") 

208 

209 assert "regs_up : in" not in vhd 

210 assert "regs_down : out" in vhd 

211 

212 assert "reg_was_read : out" not in vhd 

213 assert "reg_was_written : out" in vhd