Coverage for hdl_registers/register_field.py: 87%

45 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 abc import ABC, abstractmethod 

11 

12from .register_field_type import FieldType, Unsigned 

13 

14DEFAULT_FIELD_TYPE = Unsigned() 

15 

16 

17class RegisterField(ABC): 

18 

19 """ 

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

21 Lists a few methods that must be implemented. 

22 """ 

23 

24 @property 

25 def max_binary_value(self) -> int: 

26 """ 

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

28 field can hold given its width. 

29 

30 Returns: 

31 int: The maximum value. 

32 """ 

33 return 2**self.width - 1 

34 

35 @property 

36 def field_type(self) -> FieldType: 

37 """ 

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

39 used to interpret the bits of the field. 

40 

41 Returns: 

42 FieldType: The instanced FieldType subclass. 

43 """ 

44 return DEFAULT_FIELD_TYPE # Default for all RegisterFields 

45 

46 @property 

47 @abstractmethod 

48 def width(self): 

49 """ 

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

51 

52 Returns: 

53 int: The width. 

54 """ 

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

56 

57 @property 

58 @abstractmethod 

59 def base_index(self): 

60 """ 

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

62 

63 Returns: 

64 int: The index. 

65 """ 

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

67 

68 @property 

69 @abstractmethod 

70 def range(self): 

71 """ 

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

73 The way it shall appear in documentation. 

74 

75 Returns: 

76 str: The bit range. 

77 """ 

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

79 

80 @property 

81 @abstractmethod 

82 def default_value_str(self): 

83 """ 

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

85 in documentation. 

86 

87 Returns: 

88 str: The default value. 

89 """ 

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

91 

92 @property 

93 @abstractmethod 

94 def default_value_uint(self): 

95 """ 

96 Return a the default value as an unsigned int. 

97 

98 Returns: 

99 int: The default value. 

100 """ 

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

102 

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

104 """ 

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

106 Child classes might implement sanity checks on the value. 

107 

108 Arguments: 

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

110 

111 Returns: 

112 float: The value of the field. 

113 """ 

114 shift = self.base_index 

115 

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

117 mask = mask_at_base << shift 

118 

119 value_unsigned = (register_value & mask) >> shift 

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

121 

122 return field_value 

123 

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

125 """ 

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

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

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

129 

130 Arguments: 

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

132 

133 Returns: 

134 int: the register value 

135 """ 

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

137 max_value = self.max_binary_value 

138 if not 0 <= value_unsigned <= max_value: 

139 raise ValueError( 

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

141 ) 

142 

143 mask = max_value << self.base_index 

144 value_shifted = value_unsigned << self.base_index 

145 

146 return value_shifted & mask