Coverage for hdl_registers/generator/python/test/accessor/conftest.py: 95%

58 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 

10from __future__ import annotations 

11 

12from typing import TYPE_CHECKING, Any 

13 

14import pytest 

15from tsfpga.system_utils import load_python_module 

16 

17from hdl_registers.field.numerical_interpretation import ( 

18 Signed, 

19 SignedFixedPoint, 

20 Unsigned, 

21 UnsignedFixedPoint, 

22) 

23from hdl_registers.generator.python.accessor import PythonAccessorGenerator 

24from hdl_registers.generator.python.pickle import PythonPickleGenerator 

25from hdl_registers.register_list import RegisterList 

26from hdl_registers.register_modes import REGISTER_MODES 

27 

28if TYPE_CHECKING: 

29 from pathlib import Path 

30 

31 from hdl_registers.register_array import RegisterArray 

32 from hdl_registers.register_mode import RegisterMode 

33 

34 

35@pytest.fixture(scope="session") 

36def tmp_session_path(tmp_path_factory: pytest.TempdirFactory) -> Path: 

37 """ 

38 tmp_path that is common for all test runs in this session. 

39 Unlike the default tmp_path fixture, which is function scoped. 

40 https://stackoverflow.com/questions/70779045 

41 https://docs.pytest.org/en/6.2.x/tmpdir.html#the-tmp-path-factory-fixture 

42 """ 

43 return tmp_path_factory.mktemp("temp") 

44 

45 

46@pytest.fixture(scope="session") 

47def generate_default_accessor(tmp_session_path: Path) -> tuple[Path, Any]: 

48 """ 

49 Since all the tests use the same register list, we can save a lot of time by generating the 

50 Python code artifact only once. 

51 We run a huge amount of tests for the accessor, and the file generation takes 0.5-1 second, 

52 so the gain is significant. 

53 """ 

54 register_list = RegisterList(name="test") 

55 

56 add_test_registers(register_list_or_array=register_list) 

57 add_empty_registers(register_list_or_array=register_list) 

58 add_single_field_registers(register_list_or_array=register_list) 

59 

60 register_array = register_list.append_register_array( 

61 name="reg_array_a", length=3, description="" 

62 ) 

63 add_test_registers(register_list_or_array=register_array) 

64 add_empty_registers(register_list_or_array=register_array) 

65 add_single_field_registers(register_list_or_array=register_array) 

66 

67 PythonPickleGenerator(register_list=register_list, output_folder=tmp_session_path).create() 

68 PythonAccessorGenerator(register_list=register_list, output_folder=tmp_session_path).create() 

69 

70 python_module = load_python_module(tmp_session_path / "test_accessor.py") 

71 

72 return tmp_session_path, python_module 

73 

74 

75def add_test_registers(register_list_or_array: RegisterList | RegisterArray) -> None: 

76 for mode in REGISTER_MODES.values(): 

77 setup_test_register(register_list_or_array=register_list_or_array, mode=mode) 

78 

79 

80def setup_test_register( 

81 register_list_or_array: RegisterList | RegisterArray, mode: RegisterMode 

82) -> None: 

83 register = register_list_or_array.append_register( 

84 f"reg_{mode.shorthand}", mode=mode, description="" 

85 ) 

86 

87 register.append_bit(name="bit_aa0", description="", default_value="0") 

88 register.append_bit(name="bit_aa1", description="", default_value="1") 

89 

90 register.append_bit_vector( 

91 name="unsigned_aa", 

92 description="", 

93 width=4, 

94 default_value="0101", 

95 numerical_interpretation=Unsigned(bit_width=4), 

96 ) 

97 register.append_bit_vector( 

98 name="signed_aa", 

99 description="", 

100 width=4, 

101 default_value="1010", 

102 numerical_interpretation=Signed(bit_width=4), 

103 ) 

104 register.append_bit_vector( 

105 name="ufixed_aa", 

106 description="", 

107 width=4, 

108 default_value="0110", 

109 numerical_interpretation=UnsignedFixedPoint(1, -2), 

110 ) 

111 register.append_bit_vector( 

112 name="sfixed_aa", 

113 description="", 

114 width=4, 

115 default_value="1001", 

116 numerical_interpretation=SignedFixedPoint(0, -3), 

117 ) 

118 

119 register.append_enumeration( 

120 name="enumeration_aa", 

121 description="", 

122 elements={"element_aa0": "", "element_aa1": "", "element_aa2": ""}, 

123 default_value="element_aa1", 

124 ) 

125 

126 register.append_integer( 

127 name="uint_aa", description="", min_value=0, max_value=10, default_value=5 

128 ) 

129 register.append_integer( 

130 name="sint_aa", description="", min_value=-10, max_value=10, default_value=2 

131 ) 

132 

133 

134def add_empty_registers(register_list_or_array: RegisterList | RegisterArray) -> None: 

135 for mode in REGISTER_MODES.values(): 

136 register_list_or_array.append_register( 

137 name=f"empty_{mode.shorthand}", mode=mode, description="" 

138 ) 

139 

140 

141def add_single_field_registers(register_list_or_array: RegisterList | RegisterArray) -> None: 

142 register = register_list_or_array.append_register( 

143 "single_w_bit", mode=REGISTER_MODES["w"], description="" 

144 ) 

145 register.append_bit(name="bit_bb", description="", default_value="1") 

146 

147 register = register_list_or_array.append_register( 

148 "single_w_unsigned", mode=REGISTER_MODES["w"], description="" 

149 ) 

150 register.append_bit_vector( 

151 name="unsigned_bb", 

152 description="", 

153 width=4, 

154 default_value="1011", 

155 numerical_interpretation=Unsigned(bit_width=4), 

156 ) 

157 

158 register = register_list_or_array.append_register( 

159 "single_r_w_sfixed", mode=REGISTER_MODES["r_w"], description="" 

160 ) 

161 register.append_bit_vector( 

162 name="sfixed_bb", 

163 description="", 

164 width=4, 

165 default_value="1100", 

166 numerical_interpretation=SignedFixedPoint(1, -2), 

167 ) 

168 

169 register = register_list_or_array.append_register( 

170 "single_wpulse_enumeration", mode=REGISTER_MODES["wpulse"], description="" 

171 ) 

172 register.append_enumeration( 

173 name="enumeration_bb", 

174 description="", 

175 elements={"element_bb0": "", "element_bb1": "", "element_bb2": ""}, 

176 default_value="element_bb2", 

177 ) 

178 

179 register = register_list_or_array.append_register( 

180 "single_r_wpulse_uint", mode=REGISTER_MODES["r_wpulse"], description="" 

181 ) 

182 register.append_integer( 

183 name="uint_bb", description="", min_value=10, max_value=15, default_value=15 

184 )