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

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# -------------------------------------------------------------------------------------------------- 

9 

10# Standard libraries 

11from abc import ABC, abstractmethod 

12from typing import Union 

13 

14 

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 """ 

20 

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] 

27 

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 

37 

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 

47 

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 """ 

54 

55 def get_value(self, register_value: int) -> int: 

56 """ 

57 Get the value of this field, given the supplied register value. 

58 

59 Arguments: 

60 register_value: Value of the register that this field belongs to, 

61 as an unsigned integer. 

62 

63 Return: 

64 The value of the field as an unsigned integer. 

65 

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 

73 

74 mask_at_base = (1 << self.width) - 1 

75 mask_shifted = mask_at_base << shift_count 

76 

77 value = (register_value & mask_shifted) >> shift_count 

78 

79 return value 

80 

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. 

86 

87 Arguments: 

88 field_value: Desired unsigned integer value to set the field to. 

89 

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. 

93 

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}") 

100 

101 return field_value << self.base_index 

102 

103 @abstractmethod 

104 def __repr__(self) -> str: 

105 pass