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