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