Coverage for hdl_registers/field/register_field.py: 94%
33 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 __future__ import annotations
12from abc import ABC, abstractmethod
13from typing import TYPE_CHECKING
15if TYPE_CHECKING:
16 from .enumeration import EnumerationElement
19class RegisterField(ABC):
20 """
21 Meta class for all register fields (bits, bit vectors, integers, ...).
22 Lists a few methods that must be implemented.
23 """
25 # Must set as class members in subclasses.
26 name: str
27 _base_index: int
28 _width: int
29 description: str
30 default_value: str | int | EnumerationElement
32 @property
33 def base_index(self) -> int:
34 """
35 The index within the register for the lowest bit of this field.
36 Note that this (along with :attr:`.width`) decides the base index of upcoming fields, and
37 thus it may not be changed.
38 Hence this read-only property which is a getter for a private member.
39 """
40 return self._base_index
42 @property
43 def width(self) -> int:
44 """
45 The width, in number of bits, that this field occupies.
46 Note that this (along with :attr:`.base_index`) decides the base index of upcoming fields,
47 and thus it may not be changed.
48 Hence this read-only property which is a getter for a private member.
49 """
50 return self._width
52 @property
53 @abstractmethod
54 def default_value_uint(self) -> int:
55 """
56 Return a the default value of this field as an unsigned integer.
57 """
59 def get_value(self, register_value: int) -> int:
60 """
61 Get the value of this field, given the supplied register value.
63 Arguments:
64 register_value: Value of the register that this field belongs to,
65 as an unsigned integer.
67 Return:
68 The value of the field as an unsigned integer.
70 Note that a subclass might have a different type for the resulting value.
71 Subclasses should call this super method, and then convert the numeric value to whatever
72 type is applicable for that field.
73 Subclasses might also implement sanity checks of the value given the constraints
74 of that field.
75 """
76 shift_count = self.base_index
78 mask_at_base = (1 << self.width) - 1
79 mask_shifted = mask_at_base << shift_count
81 return (register_value & mask_shifted) >> shift_count
83 def set_value(self, field_value: int) -> int:
84 """
85 Convert the supplied value into the bit-shifted unsigned integer ready
86 to be written to the register.
87 The bits of the other fields in the register are masked out and will be set to zero.
89 Arguments:
90 field_value: Desired unsigned integer value to set the field to.
92 Note that a subclass might have a different type for this argument.
93 Subclasses should convert their argument value to an integer and call
94 this super method.
96 Return:
97 The register value as an unsigned integer.
98 """
99 max_value = 2**self.width - 1
100 if not 0 <= field_value <= max_value:
101 raise ValueError(f"Value: {field_value} is invalid for unsigned of width {self.width}")
103 return field_value << self.base_index
105 @abstractmethod
106 def __repr__(self) -> str:
107 pass