Coverage for hdl_registers/register_mode.py: 95%
41 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 dataclasses import dataclass
11from enum import Enum, auto
14@dataclass
15class _SoftwareAccessDirection:
16 name_past: str
17 name_adjective: str
20class SoftwareAccessDirection(Enum):
21 """
22 The possible directions software can access registers.
23 """
25 # The type of the enum values might change in the future.
26 # Should not make a difference for any user since the values are unique either way.
27 READ = _SoftwareAccessDirection(name_past="read", name_adjective="readable")
28 WRITE = _SoftwareAccessDirection(name_past="written", name_adjective="writeable")
31class HardwareAccessDirection(Enum):
32 """
33 The possible directions hardware can provide/read register values.
34 """
36 # The type of the enum values might change in the future.
37 # Should not make a difference for any user since the values are unique either way.
38 UP = auto()
39 DOWN = auto()
42class RegisterMode:
43 """
44 Represents a mode of a register, which defines how the register can be accessed.
45 The terms "software"/"hardware", along with "register bus", "register file", "read", "write",
46 "up" and "down" are used in this class.
47 These terms are explained by the following diagram:
49 .. code-block:: none
51 ______________________
52 | "Software" |
53 | E.g. CPU, PCIe, etc. |
54 |______________________|
55 ||
56 || "Register bus"
57 || E.g. AXI-Lite.
58 || "read" or "write" transactions.
59 ||
60 _______________________ "down" ______________________________
61 | "Register file" |--------------->| "Hardware" |
62 | E.g. generic AXI-Lite | | Meaning, your application. |
63 | register file. | "up" | In e.g. FPGA fabric or ASIC. |
64 |_______________________|<---------------|______________________________|
65 """
67 def __init__(
68 self,
69 shorthand: str,
70 name: str,
71 description: str,
72 software_can_read: bool,
73 software_can_write: bool,
74 hardware_has_up: bool,
75 ) -> None:
76 """
77 Arguments:
78 shorthand: A short string that can be used to refer to this mode.
79 E.g. "r".
80 name: A short but human-readable representation of this mode.
81 E.g. "Read".
82 description: Textual description and explanation of this mode.
83 software_can_read: True if register is readable by software on the register bus.
84 I.e. if software accessors shall have a 'read' method for registers of this mode.
85 False otherwise.
87 Analogous the ``register_file.register_file_pkg.is_read_mode`` VHDL function.
88 software_can_write: True if register is writeable by software on the register bus.
89 I.e. if software accessors shall have a 'write' method for registers of this mode.
90 False otherwise.
92 Analogous the ``register_file.register_file_pkg.is_write_mode`` VHDL function.
93 hardware_has_up: True if register gets its software-read value from hardware.
94 I.e. if register file shall have an 'up' input port for registers of this mode.
96 False otherwise, which can be due to either
98 * mode is not software-readable, or
99 * mode loopbacks a software-written value to the software read value.
100 """
101 if hardware_has_up and not software_can_read:
102 raise ValueError(
103 f'Register mode "{shorthand}"" has hardware "up", but is not software readable. '
104 "This does not make sense."
105 )
107 self.shorthand = shorthand
108 self.name = name
109 self.description = description
110 self.software_can_read = software_can_read
111 self.software_can_write = software_can_write
112 self.hardware_has_up = hardware_has_up
114 @property
115 def hardware_has_down(self) -> bool:
116 """
117 True if register provides a value from software to hardware.
118 I.e. if register file shall have a 'down' output port for registers of this mode.
120 False otherwise, which is most likely due to the register being read-only.
121 """
122 # At the moment this is the same being software-writeable.
123 # Might change in the future if we implement some exotic cool mode.
124 return self.software_can_write
126 def is_software_accessible(self, direction: SoftwareAccessDirection) -> bool:
127 """
128 Test if this mode is software-accessible in the given ``direction``.
129 Method is just a simple wrapper around the already-existing attributes.
130 """
131 if direction == SoftwareAccessDirection.READ:
132 return self.software_can_read
134 return self.software_can_write
136 def is_hardware_accessible(self, direction: HardwareAccessDirection) -> bool:
137 """
138 Test if this mode is hardware-accessible in the given ``direction``.
139 Method is just a simple wrapper around the already-existing attributes.
140 """
141 if direction == HardwareAccessDirection.UP:
142 return self.hardware_has_up
144 return self.hardware_has_down
146 def __repr__(self) -> str:
147 """
148 There should never be different modes with the same shorthand.
149 Hence, in order to make a unique representation, it is enough to use the shorthand.
150 None of the other attributes are needed.
151 """
152 return f"{self.__class__.__name__}(shorthand={self.shorthand})"
154 def __str__(self) -> str:
155 return repr(self)
157 def __eq__(self, other: object) -> bool:
158 if not isinstance(other, self.__class__):
159 return False
161 # Same logic as in __repr__.
162 return self.shorthand == other.shorthand