Coverage for hdl_registers/register.py: 100%

54 statements  

« prev     ^ index     » next       coverage.py v6.5.0, created at 2023-01-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/hdl_registers/hdl_registers 

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

9 

10# Local folder libraries 

11from .bit import Bit 

12from .bit_vector import BitVector 

13from .register_field import DEFAULT_FIELD_TYPE, FieldType 

14 

15 

16class RegisterMode: 

17 def __init__(self, mode_readable, description): 

18 """ 

19 Arguments: 

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

21 description (str): Textual description of mode. 

22 """ 

23 self.mode_readable = mode_readable 

24 self.description = description 

25 

26 

27REGISTER_MODES = dict( 

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

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

30 r_w=RegisterMode( 

31 "Read, Write", 

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

33 ), 

34 wpulse=RegisterMode( 

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

36 ), 

37 r_wpulse=RegisterMode( 

38 "Read, Write-pulse", 

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

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

41 ), 

42) 

43 

44 

45class Register: 

46 

47 """ 

48 Used to represent a register and its fields. 

49 """ 

50 

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

52 """ 

53 Arguments: 

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

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

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

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

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

59 the register list. 

60 mode (str): A valid register mode. 

61 description (str): Textual register description. 

62 """ 

63 if mode not in REGISTER_MODES: 

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

65 

66 self.name = name 

67 self.index = index 

68 self.mode = mode 

69 self.description = description 

70 self.fields = [] 

71 self.bit_index = 0 

72 

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

74 """ 

75 Append a bit field to this register. 

76 

77 Arguments: 

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

79 description (str): Description of the bit. 

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

81 

82 Return: 

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

84 """ 

85 bit = Bit( 

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

87 ) 

88 self.fields.append(bit) 

89 

90 self.bit_index += bit.width 

91 if self.bit_index > 32: 

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

93 

94 return bit 

95 

96 def append_bit_vector( 

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

98 ): 

99 """ 

100 Append a bit vector field to this register. 

101 

102 Arguments: 

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

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

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

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

107 only "1" and "0". 

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

109 

110 Return: 

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

112 """ 

113 bit_vector = BitVector( 

114 name=name, 

115 base_index=self.bit_index, 

116 description=description, 

117 width=width, 

118 default_value=default_value, 

119 field_type=field_type, 

120 ) 

121 self.fields.append(bit_vector) 

122 

123 self.bit_index += bit_vector.width 

124 if self.bit_index > 32: 

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

126 

127 return bit_vector 

128 

129 @property 

130 def default_value(self): 

131 """ 

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

133 

134 Returns: 

135 int: The default value. 

136 """ 

137 default_value = 0 

138 for field in self.fields: 

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

140 return default_value 

141 

142 def get_field(self, name): 

143 """ 

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

145 field matches. 

146 

147 Arguments: 

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

149 

150 Returns: 

151 :class:`.RegisterField`: The field. 

152 """ 

153 for field in self.fields: 

154 if field.name == name: 

155 return field 

156 

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

158 

159 @property 

160 def address(self): 

161 """ 

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

163 """ 

164 return 4 * self.index 

165 

166 @property 

167 def is_bus_readable(self): 

168 """ 

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

170 """ 

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

172 

173 @property 

174 def is_bus_writeable(self): 

175 """ 

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

177 """ 

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

179 

180 def __repr__(self): 

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

182name={self.name},\ 

183index={self.index},\ 

184mode={self.mode},\ 

185description={self.description},\ 

186default_value={self.default_value},\ 

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

188)"""