Coverage for hdl_registers/register.py: 100%

54 statements  

« prev     ^ index     » next       coverage.py v6.4.4, created at 2022-09-29 22:03 +0000

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

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

3# 

4# This file is part of the hdl_registers project, a HDL register generator fast enough to be run 

5# in real time. 

6# https://hdl-registers.com 

7# https://gitlab.com/tsfpga/hdl_registers 

8# -------------------------------------------------------------------------------------------------- 

9 

10from .bit import Bit 

11from .bit_vector import BitVector 

12from .register_field import FieldType, DEFAULT_FIELD_TYPE 

13 

14 

15class RegisterMode: 

16 def __init__(self, mode_readable, description): 

17 """ 

18 Arguments: 

19 mode_readable (str): The readable representation of this mode. E.g. "r" -> "Read-only". 

20 description (str): Textual description of mode. 

21 """ 

22 self.mode_readable = mode_readable 

23 self.description = description 

24 

25 

26REGISTER_MODES = dict( 

27 r=RegisterMode("Read", "Bus can read a value that fabric provides."), 

28 w=RegisterMode("Write", "Bus can write a value that is available for fabric usage."), 

29 r_w=RegisterMode( 

30 "Read, Write", 

31 "Bus can write a value and read it back. The written value is available for fabric usage.", 

32 ), 

33 wpulse=RegisterMode( 

34 "Write-pulse", "Bus can write a value that is asserted for one clock cycle in fabric." 

35 ), 

36 r_wpulse=RegisterMode( 

37 "Read, Write-pulse", 

38 "Bus can read a value that fabric provides. " 

39 "Bus can write a value that is asserted for one clock cycle in fabric.", 

40 ), 

41) 

42 

43 

44class Register: 

45 

46 """ 

47 Used to represent a register and its fields. 

48 """ 

49 

50 def __init__(self, name, index, mode, description): 

51 """ 

52 Arguments: 

53 name (str): The name of the register. 

54 index (int): The zero-based index of this register. 

55 If this register is part of a register array, the index shall be relative to the 

56 start of the array. I.e. the index is zero for the first register in the array. 

57 If the register is a plain register, the index shall be relative to the start of 

58 the register list. 

59 mode (str): A valid register mode. 

60 description (str): Textual register description. 

61 """ 

62 if mode not in REGISTER_MODES: 

63 raise ValueError(f'Invalid mode "{mode}" for register "{name}"') 

64 

65 self.name = name 

66 self.index = index 

67 self.mode = mode 

68 self.description = description 

69 self.fields = [] 

70 self.bit_index = 0 

71 

72 def append_bit(self, name, description, default_value): 

73 """ 

74 Append a bit field to this register. 

75 

76 Arguments: 

77 name (str): The name of the bit. 

78 description (str): Description of the bit. 

79 default_value (str): Default value. Either "1" or "0". 

80 

81 Return: 

82 :class:`.Bit`: The bit object that was created. 

83 """ 

84 bit = Bit( 

85 name=name, index=self.bit_index, description=description, default_value=default_value 

86 ) 

87 self.fields.append(bit) 

88 

89 self.bit_index += bit.width 

90 if self.bit_index > 32: 

91 raise ValueError(f'Maximum width exceeded for register "{self.name}"') 

92 

93 return bit 

94 

95 def append_bit_vector( 

96 self, name, description, width, default_value, field_type: FieldType = DEFAULT_FIELD_TYPE 

97 ): 

98 """ 

99 Append a bit vector field to this register. 

100 

101 Arguments: 

102 name (str): The name of the bit vector. 

103 width (int) : The width of the bit vector. 

104 description (str): Description of the bit vector. 

105 default_value (str): Default value as a string. Must be of length ``width`` and contain 

106 only "1" and "0". 

107 field_type (FieldType): The field type used to interpret the bits of the field. 

108 

109 Return: 

110 :class:`.BitVector`: The bit vector object that was created. 

111 """ 

112 bit_vector = BitVector( 

113 name=name, 

114 base_index=self.bit_index, 

115 description=description, 

116 width=width, 

117 default_value=default_value, 

118 field_type=field_type, 

119 ) 

120 self.fields.append(bit_vector) 

121 

122 self.bit_index += bit_vector.width 

123 if self.bit_index > 32: 

124 raise ValueError(f'Maximum width exceeded for register "{self.name}"') 

125 

126 return bit_vector 

127 

128 @property 

129 def default_value(self): 

130 """ 

131 The default value of the register. Depends on the default values of it's fields. 

132 

133 Returns: 

134 int: The default value. 

135 """ 

136 default_value = 0 

137 for field in self.fields: 

138 default_value += field.default_value_uint * 2**field.base_index 

139 return default_value 

140 

141 def get_field(self, name): 

142 """ 

143 Get the field within this register that has the given name. Will raise exception if no 

144 field matches. 

145 

146 Arguments: 

147 name (str): The name of the field. 

148 

149 Returns: 

150 :class:`.RegisterField`: The field. 

151 """ 

152 for field in self.fields: 

153 if field.name == name: 

154 return field 

155 

156 raise ValueError(f'Could not find field "{name}" within register "{self.name}"') 

157 

158 @property 

159 def address(self): 

160 """ 

161 int: Byte address, within the register list, of this register. 

162 """ 

163 return 4 * self.index 

164 

165 @property 

166 def is_bus_readable(self): 

167 """ 

168 True if the register is readable by bus. Based on the register type. 

169 """ 

170 return self.mode in ["r", "r_w", "r_wpulse"] 

171 

172 @property 

173 def is_bus_writeable(self): 

174 """ 

175 True if the register is writeable by bus. Based on the register type. 

176 """ 

177 return self.mode in ["w", "r_w", "wpulse", "r_wpulse"] 

178 

179 def __repr__(self): 

180 return f"""{self.__class__.__name__}(\ 

181name={self.name},\ 

182index={self.index},\ 

183mode={self.mode},\ 

184description={self.description},\ 

185default_value={self.default_value},\ 

186fields={','.join([repr(field) for field in self.fields])},\ 

187)"""