Coverage for hdl_registers/register_field.py: 87%

45 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# Standard libraries 

11from abc import ABC, abstractmethod 

12 

13# Local folder libraries 

14from .register_field_type import FieldType, Unsigned 

15 

16DEFAULT_FIELD_TYPE = Unsigned() 

17 

18 

19class RegisterField(ABC): 

20 

21 """ 

22 Meta class for all register fields (bits, bit vectors, integers, ...). 

23 Lists a few methods that must be implemented. 

24 """ 

25 

26 @property 

27 def max_binary_value(self) -> int: 

28 """ 

29 Get the maximum value, represented as a positive integer, that this 

30 field can hold given its width. 

31 

32 Returns: 

33 int: The maximum value. 

34 """ 

35 return 2**self.width - 1 

36 

37 @property 

38 def field_type(self) -> FieldType: 

39 """ 

40 The field type (Unsigned, Signed, UnsignedFixedPoint, SignedFixedPoint...) 

41 used to interpret the bits of the field. 

42 

43 Returns: 

44 FieldType: The instanced FieldType subclass. 

45 """ 

46 return DEFAULT_FIELD_TYPE # Default for all RegisterFields 

47 

48 @property 

49 @abstractmethod 

50 def width(self): 

51 """ 

52 Return the width, in number of bits, that this field occupies. 

53 

54 Returns: 

55 int: The width. 

56 """ 

57 raise NotImplementedError("Must be implemented in child class") 

58 

59 @property 

60 @abstractmethod 

61 def base_index(self): 

62 """ 

63 The index within the register for the lowest bit of this Field. 

64 

65 Returns: 

66 int: The index. 

67 """ 

68 raise NotImplementedError("Must be implemented in child class") 

69 

70 @property 

71 @abstractmethod 

72 def range(self): 

73 """ 

74 Return the bits that this field occupies in a readable format. 

75 The way it shall appear in documentation. 

76 

77 Returns: 

78 str: The bit range. 

79 """ 

80 raise NotImplementedError("Must be implemented in child class") 

81 

82 @property 

83 @abstractmethod 

84 def default_value_str(self): 

85 """ 

86 Return a formatted string of the default value. The way it shall appear 

87 in documentation. 

88 

89 Returns: 

90 str: The default value. 

91 """ 

92 raise NotImplementedError("Must be implemented in child class") 

93 

94 @property 

95 @abstractmethod 

96 def default_value_uint(self): 

97 """ 

98 Return a the default value as an unsigned int. 

99 

100 Returns: 

101 int: The default value. 

102 """ 

103 raise NotImplementedError("Must be implemented in child class") 

104 

105 def get_value(self, register_value: int) -> float: 

106 """ 

107 Get the value of this field, given the supplied register value. 

108 Child classes might implement sanity checks on the value. 

109 

110 Arguments: 

111 register_value (int): Value of the register that this field belongs to. 

112 

113 Returns: 

114 float: The value of the field. 

115 """ 

116 shift = self.base_index 

117 

118 mask_at_base = (1 << self.width) - 1 

119 mask = mask_at_base << shift 

120 

121 value_unsigned = (register_value & mask) >> shift 

122 field_value = self.field_type.convert_from_unsigned_binary(self.width, value_unsigned) 

123 

124 return field_value 

125 

126 def set_value(self, field_value: float) -> int: 

127 """ 

128 Convert the supplied value into the bit-shifted unsigned integer ready 

129 to be written to the register. The bits of the other fields in the 

130 register are masked out and will be set to zero. 

131 

132 Arguments: 

133 field_value (float) : Desired value to set the field to. 

134 

135 Returns: 

136 int: the register value 

137 """ 

138 value_unsigned = self.field_type.convert_to_unsigned_binary(self.width, field_value) 

139 max_value = self.max_binary_value 

140 if not 0 <= value_unsigned <= max_value: 

141 raise ValueError( 

142 f"Value: {value_unsigned} is invalid for unsigned of width {self.width}" 

143 ) 

144 

145 mask = max_value << self.base_index 

146 value_shifted = value_unsigned << self.base_index 

147 

148 return value_shifted & mask