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
« 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# --------------------------------------------------------------------------------------------------
10from .constant import Constant
13class BitVectorConstant(Constant):
14 """
15 Represent a bit vector constant.
16 See :ref:`constant_bit_vector` for details.
17 """
19 separator_character = "_"
20 allowed_binary_characters = "01" + separator_character
21 allowed_hexadecimal_characters = "0123456789abcdefABCDEF" + separator_character
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.
32 For example ``0b1111``, ``0x0001_AAFF``, ``0x43C00000``.
33 description: Textual description for the constant.
34 """
35 self.name = name
36 self.description = description
38 # Assigned in 'value' setter.
39 self._is_hexadecimal_not_binary = False
40 self._prefix = ""
42 self._value = ""
43 # Assign self._value via setter
44 self.value = value
46 @property
47 def prefix(self) -> str:
48 """
49 Getter for ``prefix``.
50 """
51 return self._prefix
53 @property
54 def value(self) -> str:
55 """
56 Getter for ``value``.
57 """
58 return self._value
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 )
70 self._prefix = value[0:2]
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 )
77 self._is_hexadecimal_not_binary = self._prefix == "0x"
79 # Assign only the numeric characters
80 self._value = value[2:]
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 )
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, "")
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
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
115 return len(self.value_without_separator) * bits_per_character
117 def __repr__(self) -> str:
118 return f"""{self.__class__.__name__}(\
119name={self.name},\
120prefix={self.prefix},\
121value={self.value},\
122description={self.description},\
123)"""
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 """
133 # https://docs.astral.sh/ruff/rules/no-slots-in-str-subclass/
134 __slots__ = ()
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 """