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

46 statements  

« prev     ^ index     » next       coverage.py v7.6.3, created at 2024-10-17 20:51 +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 

10# Standard libraries 

11from typing import Optional 

12 

13# Local folder libraries 

14from .constant import Constant 

15 

16 

17class BitVectorConstant(Constant): 

18 separator_character = "_" 

19 allowed_binary_characters = "01" + separator_character 

20 allowed_hexadecimal_characters = "0123456789abcdefABCDEF" + separator_character 

21 

22 def __init__(self, name: str, value: str, description: Optional[str] = None): 

23 """ 

24 Arguments: 

25 name: The name of the constant. 

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

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

28 description: Textual description for the constant. 

29 """ 

30 self.name = name 

31 self.description = "" if description is None else description 

32 

33 # Assigned in 'value' setter. 

34 self._is_hexadecimal_not_binary = False 

35 self._prefix = "" 

36 

37 self._value = "" 

38 # Assign self._value via setter 

39 self.value = value 

40 

41 @property 

42 def prefix(self) -> str: 

43 """ 

44 Getter for ``prefix``. 

45 """ 

46 return self._prefix 

47 

48 @property 

49 def value(self) -> str: 

50 """ 

51 Getter for ``value``. 

52 """ 

53 return self._value 

54 

55 @value.setter 

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

57 """ 

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

59 """ 

60 if not isinstance(value, str): 

61 raise TypeError( 

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

63 ) 

64 

65 self._prefix = value[0:2] 

66 

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

68 raise ValueError( 

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

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

71 ) 

72 

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

74 

75 # Assign only the numeric characters 

76 self._value = value[2:] 

77 

78 allowed_characters = ( 

79 self.allowed_hexadecimal_characters 

80 if self._is_hexadecimal_not_binary 

81 else self.allowed_binary_characters 

82 ) 

83 for character in self._value: 

84 if character not in allowed_characters: 

85 raise ValueError( 

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

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

88 ) 

89 

90 @property 

91 def value_without_separator(self) -> str: 

92 """ 

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

94 """ 

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

96 

97 @property 

98 def is_hexadecimal_not_binary(self) -> bool: 

99 """ 

100 Getter for ``is_hexadecimal_not_binary``. 

101 """ 

102 return self._is_hexadecimal_not_binary 

103 

104 @property 

105 def width(self) -> int: 

106 """ 

107 The number of bits this vector constant occupies. 

108 """ 

109 bits_per_character = 4 if self._is_hexadecimal_not_binary else 1 

110 

111 return len(self.value_without_separator) * bits_per_character 

112 

113 def __repr__(self) -> str: 

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

115name={self.name},\ 

116prefix={self.prefix},\ 

117value={self.value},\ 

118description={self.description},\ 

119)""" 

120 

121 

122class UnsignedVector(str): 

123 """ 

124 Represent a value that is of type unsigned vector 

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

126 :class:`.UnsignedVectorConstant` class). 

127 """ 

128 

129 

130class UnsignedVectorConstant(BitVectorConstant): 

131 """ 

132 Represent a register constant that is of type unsigned vector 

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

134 :class:`.UnsignedVector` class). 

135 """