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

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 dataclasses import dataclass 

12from enum import Enum, auto 

13from typing import Any 

14 

15 

16@dataclass 

17class _SoftwareAccessDirection: 

18 name_past: str 

19 name_adjective: str 

20 

21 

22class SoftwareAccessDirection(Enum): 

23 """ 

24 The possible directions software can access registers. 

25 """ 

26 

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

31 

32 

33class HardwareAccessDirection(Enum): 

34 """ 

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

36 """ 

37 

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

42 

43 

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: 

50 

51 .. code-block:: none 

52 

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

68 

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. 

88 

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. 

93 

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. 

97 

98 False otherwise, which can be due to either 

99 

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 ) 

107 

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 

114 

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. 

120 

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 

126 

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 

134 

135 return self.software_can_write 

136 

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 

144 

145 return self.hardware_has_down 

146 

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

154 

155 def __str__(self) -> str: 

156 return repr(self) 

157 

158 def __eq__(self, other: Any) -> bool: 

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

160 return False 

161 

162 # Same logic as in __repr__. 

163 return self.shorthand == other.shorthand