Coverage for hdl_registers/constant/bit_vector_constant.py: 100%
46 statements
« prev ^ index » next coverage.py v7.6.9, created at 2024-12-19 20:51 +0000
« prev ^ index » next coverage.py v7.6.9, created at 2024-12-19 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# --------------------------------------------------------------------------------------------------
10# Standard libraries
11from typing import Optional
13# Local folder libraries
14from .constant import Constant
17class BitVectorConstant(Constant):
18 separator_character = "_"
19 allowed_binary_characters = "01" + separator_character
20 allowed_hexadecimal_characters = "0123456789abcdefABCDEF" + separator_character
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
33 # Assigned in 'value' setter.
34 self._is_hexadecimal_not_binary = False
35 self._prefix = ""
37 self._value = ""
38 # Assign self._value via setter
39 self.value = value
41 @property
42 def prefix(self) -> str:
43 """
44 Getter for ``prefix``.
45 """
46 return self._prefix
48 @property
49 def value(self) -> str:
50 """
51 Getter for ``value``.
52 """
53 return self._value
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 )
65 self._prefix = value[0:2]
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 )
73 self._is_hexadecimal_not_binary = self._prefix == "0x"
75 # Assign only the numeric characters
76 self._value = value[2:]
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 )
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, "")
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
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
111 return len(self.value_without_separator) * bits_per_character
113 def __repr__(self) -> str:
114 return f"""{self.__class__.__name__}(\
115name={self.name},\
116prefix={self.prefix},\
117value={self.value},\
118description={self.description},\
119)"""
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 """
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 """