Coverage for hdl_registers/constant/bit_vector_constant.py: 100%

46 statements  

« prev     ^ index     » next       coverage.py v7.8.0, created at 2025-04-29 06:41 +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 .constant import Constant 

11 

12 

13class BitVectorConstant(Constant): 

14 """ 

15 Represent a bit vector constant. 

16 See :ref:`constant_bit_vector` for details. 

17 """ 

18 

19 separator_character = "_" 

20 allowed_binary_characters = "01" + separator_character 

21 allowed_hexadecimal_characters = "0123456789abcdefABCDEF" + separator_character 

22 

23 def __init__(self, name: str, value: str, description: str = "") -> None: 

24 """ 

25 Arguments: 

26 name: The name of the constant. 

27 value: The constant value. 

28 Must start with "0b" or "0x". 

29 Must only contain legal binary or hexadecimal characters. 

30 Underscore may be used as a separator. 

31 

32 For example ``0b1111``, ``0x0001_AAFF``, ``0x43C00000``. 

33 description: Textual description for the constant. 

34 """ 

35 self.name = name 

36 self.description = description 

37 

38 # Assigned in 'value' setter. 

39 self._is_hexadecimal_not_binary = False 

40 self._prefix = "" 

41 

42 self._value = "" 

43 # Assign self._value via setter 

44 self.value = value 

45 

46 @property 

47 def prefix(self) -> str: 

48 """ 

49 Getter for ``prefix``. 

50 """ 

51 return self._prefix 

52 

53 @property 

54 def value(self) -> str: 

55 """ 

56 Getter for ``value``. 

57 """ 

58 return self._value 

59 

60 @value.setter 

61 def value(self, value: str) -> None: 

62 """ 

63 Setter for ``value`` that performs sanity checks. 

64 """ 

65 if not isinstance(value, str): 

66 raise TypeError( 

67 f'Constant "{self.name}" has invalid data type "{type(value)}". Value: "{value}".' 

68 ) 

69 

70 self._prefix = value[0:2] 

71 

72 if len(value) < 3 or self._prefix not in ["0b", "0x"]: 

73 raise ValueError( 

74 f'Constant "{self.name}" value must start with a correct prefix. Value: "{value}".' 

75 ) 

76 

77 self._is_hexadecimal_not_binary = self._prefix == "0x" 

78 

79 # Assign only the numeric characters 

80 self._value = value[2:] 

81 

82 allowed_characters = ( 

83 self.allowed_hexadecimal_characters 

84 if self._is_hexadecimal_not_binary 

85 else self.allowed_binary_characters 

86 ) 

87 for character in self._value: 

88 if character not in allowed_characters: 

89 raise ValueError( 

90 f'Constant "{self.name}" contains illegal character "{character}". ' 

91 f'Value: "{value}".' 

92 ) 

93 

94 @property 

95 def value_without_separator(self) -> str: 

96 """ 

97 Getter for ``value``, without any separator characters. 

98 """ 

99 return self._value.replace(self.separator_character, "") 

100 

101 @property 

102 def is_hexadecimal_not_binary(self) -> bool: 

103 """ 

104 Getter for ``is_hexadecimal_not_binary``. 

105 """ 

106 return self._is_hexadecimal_not_binary 

107 

108 @property 

109 def width(self) -> int: 

110 """ 

111 The number of bits this vector constant occupies. 

112 """ 

113 bits_per_character = 4 if self._is_hexadecimal_not_binary else 1 

114 

115 return len(self.value_without_separator) * bits_per_character 

116 

117 def __repr__(self) -> str: 

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

119name={self.name},\ 

120prefix={self.prefix},\ 

121value={self.value},\ 

122description={self.description},\ 

123)""" 

124 

125 

126class UnsignedVector(str): 

127 """ 

128 Represent a **value** that is of type unsigned vector 

129 (as opposed to a **register constant** of the same type, which would use the 

130 :class:`.UnsignedVectorConstant` class). 

131 """ 

132 

133 # https://docs.astral.sh/ruff/rules/no-slots-in-str-subclass/ 

134 __slots__ = () 

135 

136 

137class UnsignedVectorConstant(BitVectorConstant): 

138 """ 

139 Represent a **register constant** that is of type unsigned vector 

140 (as opposed to a **plain value** of the same type in Python, which would use the 

141 :class:`.UnsignedVector` class). 

142 """