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
« 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# --------------------------------------------------------------------------------------------------
10from .constant import Constant
13class BitVectorConstant(Constant):
14 separator_character = "_"
15 allowed_binary_characters = "01" + separator_character
16 allowed_hexadecimal_characters = "0123456789abcdefABCDEF" + separator_character
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
29 # Assigned in 'value' setter.
30 self._is_hexadecimal_not_binary = False
31 self._prefix = ""
33 self._value = ""
34 # Assign self._value via setter
35 self.value = value
37 @property
38 def prefix(self) -> str:
39 """
40 Getter for ``prefix``.
41 """
42 return self._prefix
44 @property
45 def value(self) -> str:
46 """
47 Getter for ``value``.
48 """
49 return self._value
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 )
61 self._prefix = value[0:2]
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 )
68 self._is_hexadecimal_not_binary = self._prefix == "0x"
70 # Assign only the numeric characters
71 self._value = value[2:]
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 )
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, "")
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
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
106 return len(self.value_without_separator) * bits_per_character
108 def __repr__(self) -> str:
109 return f"""{self.__class__.__name__}(\
110name={self.name},\
111prefix={self.prefix},\
112value={self.value},\
113description={self.description},\
114)"""
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 """
124 # https://docs.astral.sh/ruff/rules/no-slots-in-str-subclass/
125 __slots__ = ()
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 """