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

46 statements  

« prev     ^ index     » next       coverage.py v7.6.12, created at 2025-03-12 11:11 +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 separator_character = "_" 

15 allowed_binary_characters = "01" + separator_character 

16 allowed_hexadecimal_characters = "0123456789abcdefABCDEF" + separator_character 

17 

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

19 """ 

20 Arguments: 

21 name: The name of the constant. 

22 value: The constant value. Must start with "0b" or "0x". Must only contain legal binary 

23 or hexadecimal characters. Underscore may be used as a separator. 

24 description: Textual description for the constant. 

25 """ 

26 self.name = name 

27 self.description = description 

28 

29 # Assigned in 'value' setter. 

30 self._is_hexadecimal_not_binary = False 

31 self._prefix = "" 

32 

33 self._value = "" 

34 # Assign self._value via setter 

35 self.value = value 

36 

37 @property 

38 def prefix(self) -> str: 

39 """ 

40 Getter for ``prefix``. 

41 """ 

42 return self._prefix 

43 

44 @property 

45 def value(self) -> str: 

46 """ 

47 Getter for ``value``. 

48 """ 

49 return self._value 

50 

51 @value.setter 

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

53 """ 

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

55 """ 

56 if not isinstance(value, str): 

57 raise TypeError( 

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

59 ) 

60 

61 self._prefix = value[0:2] 

62 

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

64 raise ValueError( 

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

66 ) 

67 

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

69 

70 # Assign only the numeric characters 

71 self._value = value[2:] 

72 

73 allowed_characters = ( 

74 self.allowed_hexadecimal_characters 

75 if self._is_hexadecimal_not_binary 

76 else self.allowed_binary_characters 

77 ) 

78 for character in self._value: 

79 if character not in allowed_characters: 

80 raise ValueError( 

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

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

83 ) 

84 

85 @property 

86 def value_without_separator(self) -> str: 

87 """ 

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

89 """ 

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

91 

92 @property 

93 def is_hexadecimal_not_binary(self) -> bool: 

94 """ 

95 Getter for ``is_hexadecimal_not_binary``. 

96 """ 

97 return self._is_hexadecimal_not_binary 

98 

99 @property 

100 def width(self) -> int: 

101 """ 

102 The number of bits this vector constant occupies. 

103 """ 

104 bits_per_character = 4 if self._is_hexadecimal_not_binary else 1 

105 

106 return len(self.value_without_separator) * bits_per_character 

107 

108 def __repr__(self) -> str: 

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

110name={self.name},\ 

111prefix={self.prefix},\ 

112value={self.value},\ 

113description={self.description},\ 

114)""" 

115 

116 

117class UnsignedVector(str): 

118 """ 

119 Represent a value that is of type unsigned vector 

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

121 :class:`.UnsignedVectorConstant` class). 

122 """ 

123 

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

125 __slots__ = () 

126 

127 

128class UnsignedVectorConstant(BitVectorConstant): 

129 """ 

130 Represent a register constant that is of type unsigned vector 

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

132 :class:`.UnsignedVector` class). 

133 """