Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1# -------------------------------------------------------------------------------------------------- 

2# Copyright (c) Lukas Vik. All rights reserved. 

3# 

4# This file is part of the tsfpga project. 

5# https://tsfpga.com 

6# https://gitlab.com/tsfpga/tsfpga 

7# -------------------------------------------------------------------------------------------------- 

8 

9from tsfpga.system_utils import create_file, read_file 

10from tsfpga.vhdl_file_documentation import VhdlFileDocumentation 

11 

12 

13class ModuleDocumentation: 

14 

15 """ 

16 Methods for generating a reStructuredText document with module documentation. 

17 The content is extracted from VHDL source file headers. 

18 """ 

19 

20 def __init__(self, module): 

21 """ 

22 Arguments: 

23 module (:class:`.BaseModule`): The module which shall be documented. 

24 """ 

25 self._module = module 

26 

27 def get_overview_rst(self): 

28 """ 

29 Get the contents of the module's ``doc/<name>.rst``, i.e. the module "overview" document. 

30 

31 Return: 

32 str: Module overview RST. ``None`` if file does not exist. 

33 """ 

34 overview_rst_file = self._module.path / "doc" / f"{self._module.name}.rst" 

35 if overview_rst_file.exists(): 

36 return read_file(overview_rst_file) 

37 

38 return None 

39 

40 def get_register_rst(self, heading_character): 

41 """ 

42 Get an RST snippet with a link to the module's register documentation, if available. 

43 Note that this will create an RST ``:download:`` statement to the register .html page. 

44 When building, the ``.html`` file must be present in the same directory as the 

45 ``.rst`` file. 

46 This is done automatically by :meth:`.create_rst_document`. 

47 

48 Arguments: 

49 heading_character (str): Character to use for heading underline. 

50 

51 Return: 

52 str: RST snippet with link to register HTML. ``None`` if module does not have registers. 

53 """ 

54 if self._module.registers is not None: 

55 heading = "Register interface" 

56 heading_underline = heading_character * len(heading) 

57 return f"""\ 

58.. _{self._module.name}.register_interface: 

59 

60{heading} 

61{heading_underline} 

62 

63This module has register definitions. 

64Please see :download:`separate HTML page <{self._module.name}_regs.html>` for \ 

65register documentation. 

66""" 

67 

68 return None 

69 

70 def get_submodule_rst(self, heading_character, exclude_files=None): 

71 """ 

72 Get RST code with documentation of the different sub-modules (files) of the module. 

73 Contains documentation that is extracted from the file headers, as well as a 

74 symbolator symbol of the entity. 

75 

76 Arguments: 

77 heading_character (str): Character to use for heading underline. 

78 

79 Return: 

80 str: RST code with sub-module documentation. 

81 """ 

82 exclude_files = {} if exclude_files is None else exclude_files 

83 

84 rst = "" 

85 

86 for hdl_file in self._get_vhdl_files(exclude_files): 

87 vhdl_file_path = hdl_file.path 

88 

89 vhdl_file_documentation = VhdlFileDocumentation(vhdl_file_path) 

90 

91 file_rst = vhdl_file_documentation.get_header_rst() 

92 file_rst = "" if file_rst is None else file_rst 

93 

94 symbolator_rst = self._get_symbolator_rst(vhdl_file_documentation) 

95 symbolator_rst = "" if symbolator_rst is None else symbolator_rst 

96 

97 entity_name = vhdl_file_path.stem 

98 heading = f"Sub-module {vhdl_file_path.name}" 

99 heading_underline = heading_character * len(heading) 

100 rst += f""" 

101.. _{self._module.name}.{entity_name}: 

102 

103{heading} 

104{heading_underline} 

105 

106{symbolator_rst} 

107 

108{file_rst} 

109""" 

110 

111 return rst 

112 

113 def get_rst_document(self): 

114 """ 

115 Get a complete RST document with the content of :meth:`.get_overview_rst`, 

116 :meth:`.get_register_rst`, and :meth:`.get_submodule_rst`, as well as a top level heading. 

117 

118 Returns: 

119 str: An RST document. 

120 """ 

121 heading_character_1 = "=" 

122 heading_character_2 = "-" 

123 

124 heading = f"Module {self._module.name}" 

125 heading_underline = heading_character_1 * len(heading) 

126 

127 overview_rst = self.get_overview_rst() 

128 overview_rst = "" if overview_rst is None else overview_rst 

129 

130 registers_rst = self.get_register_rst(heading_character=heading_character_2) 

131 registers_rst = "" if registers_rst is None else registers_rst 

132 

133 submodule_rst = self.get_submodule_rst(heading_character=heading_character_2) 

134 

135 rst = f"""\ 

136 

137.. _module_{self._module.name}: 

138 

139{heading} 

140{heading_underline} 

141 

142This document contains technical documentation for the ``{self._module.name}`` module. 

143 

144{overview_rst} 

145 

146{registers_rst} 

147 

148{submodule_rst} 

149""" 

150 

151 return rst 

152 

153 def create_rst_document(self, output_path): 

154 """ 

155 Create an ``.rst`` file in ``output_path`` with the content from :meth:`.get_rst_document`. 

156 If the module has registers, the HTML page will also be generated in ``output_path``, so 

157 that e.g. sphinx can be run directly. 

158 

159 Arguments: 

160 output_path (`pathlib.Path`): Document will be placed here. 

161 """ 

162 register_list = self._module.registers 

163 if register_list is not None: 

164 register_list.create_html_page(output_path) 

165 

166 create_file(output_path / f"{self._module.name}.rst", contents=self.get_rst_document()) 

167 

168 def _get_vhdl_files(self, exclude_files): 

169 """ 

170 Get VHDL files that shall be included in the documentation, in order. 

171 """ 

172 hdl_files = self._module.get_synthesis_files(files_avoid=exclude_files) 

173 

174 module_regs_pkg = self._module.path / f"{self._module.name}_regs_pkg.vhd" 

175 vhdl_files = [] 

176 for hdl_file in hdl_files: 

177 if hdl_file.is_vhdl and hdl_file.path != module_regs_pkg: 

178 vhdl_files.append(hdl_file) 

179 

180 # Sort by file name 

181 def sort_key(vhdl_file): 

182 return vhdl_file.path.name 

183 

184 vhdl_files = sorted(vhdl_files, key=sort_key) 

185 

186 return vhdl_files 

187 

188 @staticmethod 

189 def _get_symbolator_rst(vhdl_file_documentation): 

190 """ 

191 Get RST for rendering a symbolator component. 

192 """ 

193 component = vhdl_file_documentation.get_symbolator_component() 

194 if component is None: 

195 return "" 

196 

197 indent = " " 

198 rst = ".. symbolator::\n\n" 

199 rst += indent + component.replace("\n", f"\n{indent}") 

200 

201 return rst