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

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 

10from dataclasses import dataclass 

11from enum import Enum, auto 

12 

13 

14@dataclass 

15class _SoftwareAccessDirection: 

16 name_past: str 

17 name_adjective: str 

18 

19 

20class SoftwareAccessDirection(Enum): 

21 """ 

22 The possible directions software can access registers. 

23 """ 

24 

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

29 

30 

31class HardwareAccessDirection(Enum): 

32 """ 

33 The possible directions hardware can provide/read register values. 

34 """ 

35 

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() 

40 

41 

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: 

48 

49 .. code-block:: none 

50 

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

66 

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. 

86 

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. 

91 

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. 

95 

96 False otherwise, which can be due to either 

97 

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 ) 

106 

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 

113 

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. 

119 

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 

125 

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 

133 

134 return self.software_can_write 

135 

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 

143 

144 return self.hardware_has_down 

145 

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

153 

154 def __str__(self) -> str: 

155 return repr(self) 

156 

157 def __eq__(self, other: object) -> bool: 

158 if not isinstance(other, self.__class__): 

159 return False 

160 

161 # Same logic as in __repr__. 

162 return self.shorthand == other.shorthand