blob: 072cc2d4dc0aba0beaac13ed2e47210545756be6 [file] [log] [blame]
lowRISC Contributors802543a2019-08-31 12:12:56 +01001#!/usr/bin/env python3
2# Copyright lowRISC contributors.
3# Licensed under the Apache License, Version 2.0, see LICENSE for details.
4# SPDX-License-Identifier: Apache-2.0
5#
lowRISC Contributors802543a2019-08-31 12:12:56 +01006# Usage:
7# run './build_docs.py' to generate the documentation and keep it updated
Garret Kelly9eebde02019-10-22 15:36:49 -04008# open 'http://localhost:1313/' to check live update (this opens the top
lowRISC Contributors802543a2019-08-31 12:12:56 +01009# level index page). you can also directly access a specific document by
Garret Kelly9eebde02019-10-22 15:36:49 -040010# accessing 'http://localhost:1313/path/to/doc',
11# e.g. http://localhost:1313/hw/ip/uart/doc
lowRISC Contributors802543a2019-08-31 12:12:56 +010012
13import argparse
14import logging
15import os
Philipp Wagnercd57f862019-10-31 14:20:39 +000016import platform
Silvestrs Timofejevsecaf87c2019-11-12 21:52:57 +000017import re
Garret Kelly9eebde02019-10-22 15:36:49 -040018import subprocess
Tobias Wölfel19a86e22020-05-14 14:31:00 +020019import sys
Sam Elliott692078c2020-02-07 17:23:21 +000020import textwrap
Martin Lueker-Bodendcd6c682021-05-16 21:20:10 -070021import socket
lowRISC Contributors802543a2019-08-31 12:12:56 +010022from pathlib import Path
23
Philipp Wagner2e217a92020-10-09 12:19:08 +020024import check_tool_requirements
Garret Kelly9eebde02019-10-22 15:36:49 -040025import dashboard.gen_dashboard_entry as gen_dashboard_entry
Sam Elliottb6745d32020-04-08 21:46:28 +010026import difgen.gen_dif_listing as gen_dif_listing
Srikrishna Iyer86169d02021-05-10 09:35:52 -070027import dvsim.Testplan as Testplan
Garret Kelly9eebde02019-10-22 15:36:49 -040028import reggen.gen_cfg_html as gen_cfg_html
29import reggen.gen_html as gen_html
Eunchan Kim9790e3e2019-11-01 15:17:32 -070030import reggen.gen_selfdoc as reggen_selfdoc
Eunchan Kim9790e3e2019-11-01 15:17:32 -070031import tlgen
Rupert Swarbrick269bb3d2021-02-23 15:41:56 +000032from reggen.ip_block import IpBlock
lowRISC Contributors802543a2019-08-31 12:12:56 +010033
34USAGE = """
35 build_docs [options]
36"""
37
Philipp Wagnercd57f862019-10-31 14:20:39 +000038# Version of hugo extended to be used to build the docs
Philipp Wagner2e217a92020-10-09 12:19:08 +020039try:
Rupert Swarbrick9ab407e2021-01-25 11:40:17 +000040 TOOL_REQUIREMENTS = check_tool_requirements.read_tool_requirements()
41 HUGO_EXTENDED_VERSION = TOOL_REQUIREMENTS['hugo_extended'].min_version
Philipp Wagner2e217a92020-10-09 12:19:08 +020042except Exception as e:
43 print("Unable to get required hugo version: %s" % str(e), file=sys.stderr)
44 sys.exit(1)
Philipp Wagnercd57f862019-10-31 14:20:39 +000045
lowRISC Contributors802543a2019-08-31 12:12:56 +010046# Configurations
Tobias Wölfel7840d7b2019-10-07 12:29:33 +020047# TODO: Move to config.yaml
lowRISC Contributors802543a2019-08-31 12:12:56 +010048SRCTREE_TOP = Path(__file__).parent.joinpath('..').resolve()
49config = {
50 # Toplevel source directory
Garret Kelly9eebde02019-10-22 15:36:49 -040051 "topdir":
52 SRCTREE_TOP,
lowRISC Contributors802543a2019-08-31 12:12:56 +010053
Garret Kelly9eebde02019-10-22 15:36:49 -040054 # Pre-generate register and hwcfg fragments from these files.
55 "hardware_definitions": [
56 "hw/ip/aes/data/aes.hjson",
Tom Roberts7f173f22020-12-01 14:29:31 +000057 "hw/ip/aon_timer/data/aon_timer.hjson",
Sam Elliottd834c702020-02-12 11:18:47 +000058 "hw/top_earlgrey/ip/alert_handler/data/autogen/alert_handler.hjson",
Mark Branstad4efd35e2019-12-19 15:44:45 +000059 "hw/ip/entropy_src/data/entropy_src.hjson",
Martin Lueker-Bodenc76cbc72020-07-21 21:13:35 +000060 "hw/ip/csrng/data/csrng.hjson",
Eric Shiu5f1d3042021-03-17 17:24:11 -070061 "hw/ip/adc_ctrl/data/adc_ctrl.hjson",
Martin Lueker-Boden94bfa222020-09-25 12:27:31 -070062 "hw/ip/edn/data/edn.hjson",
Garret Kelly9eebde02019-10-22 15:36:49 -040063 "hw/ip/flash_ctrl/data/flash_ctrl.hjson",
64 "hw/ip/gpio/data/gpio.hjson",
65 "hw/ip/hmac/data/hmac.hjson",
66 "hw/ip/i2c/data/i2c.hjson",
Timothy Chenc2e3f052020-09-10 18:47:25 -070067 "hw/ip/keymgr/data/keymgr.hjson",
Eunchan Kim4096f7d2020-10-20 17:55:47 -070068 "hw/ip/kmac/data/kmac.hjson",
Michael Schaffnere81ab752020-09-30 18:57:29 -070069 "hw/ip/lc_ctrl/data/lc_ctrl.hjson",
Philipp Wagner05a5f142020-06-03 23:42:20 +010070 "hw/ip/otbn/data/otbn.hjson",
Michael Schaffner41319c22020-04-12 15:40:24 -070071 "hw/ip/otp_ctrl/data/otp_ctrl.hjson",
Martin Lueker-Boden4d4acea2020-08-22 15:23:43 -070072 "hw/ip/pattgen/data/pattgen.hjson",
Martin Lueker-Boden5dd1bfb2020-11-15 21:18:59 -080073 "hw/ip/pwm/data/pwm.hjson",
Rupert Swarbrickcd5d00e2020-12-02 08:41:35 +000074 "hw/ip/rom_ctrl/data/rom_ctrl.hjson",
Sam Elliottd834c702020-02-12 11:18:47 +000075 "hw/top_earlgrey/ip/pinmux/data/autogen/pinmux.hjson",
Timothy Chen375be342020-11-02 12:55:09 -080076 "hw/top_earlgrey/ip/clkmgr/data/autogen/clkmgr.hjson",
Timothy Chend7d6e0f2020-08-11 18:59:50 -070077 "hw/top_earlgrey/ip/pwrmgr/data/autogen/pwrmgr.hjson",
Timothy Chen1e68dd82020-09-22 16:20:17 -070078 "hw/top_earlgrey/ip/rstmgr/data/autogen/rstmgr.hjson",
Timothy Chen244a8dd2021-04-23 16:11:25 -070079 "hw/top_earlgrey/ip/sensor_ctrl/data/sensor_ctrl.hjson",
Timothy Chen1e68dd82020-09-22 16:20:17 -070080 "hw/top_earlgrey/ip/rv_plic/data/autogen/rv_plic.hjson",
Timothy Chen576cc082021-07-21 17:42:48 -070081 "hw/ip/rv_core_ibex/data/rv_core_ibex.hjson",
Garret Kelly9eebde02019-10-22 15:36:49 -040082 "hw/ip/rv_timer/data/rv_timer.hjson",
Martin Lueker-Bodeneb9498c2021-02-02 08:33:29 -080083 "hw/ip/spi_host/data/spi_host.hjson",
Garret Kelly9eebde02019-10-22 15:36:49 -040084 "hw/ip/spi_device/data/spi_device.hjson",
Michael Schaffner86c0e322020-10-07 19:56:32 -070085 "hw/ip/sram_ctrl/data/sram_ctrl.hjson",
Eric Shiu97b905a2021-04-09 15:11:27 -070086 "hw/ip/sysrst_ctrl/data/sysrst_ctrl.hjson",
Garret Kelly9eebde02019-10-22 15:36:49 -040087 "hw/ip/uart/data/uart.hjson",
88 "hw/ip/usbdev/data/usbdev.hjson",
89 "hw/ip/usbuart/data/usbuart.hjson",
90 ],
91
92 # Pre-generate dashboard fragments from these directories.
Philipp Wagner8171ede2021-03-15 21:47:01 +000093 "dashboard_definitions": {
94 "comportable": [
95 "hw/ip",
Timothy Chen244a8dd2021-04-23 16:11:25 -070096 "hw/top_earlgrey/ip/sensor_ctrl"
Philipp Wagner8171ede2021-03-15 21:47:01 +000097 ],
98 },
Garret Kelly9eebde02019-10-22 15:36:49 -040099
100 # Pre-generate testplan fragments from these files.
101 "testplan_definitions": [
Rasmus Madsen206784b2019-11-13 14:55:04 -0800102 "hw/ip/aes/data/aes_testplan.hjson",
Cindy Chen70f9ca52019-12-02 16:32:58 -0800103 "hw/ip/alert_handler/data/alert_handler_testplan.hjson",
Srikrishna Iyer1abc7b92021-03-08 21:46:49 -0800104 "hw/ip/aon_timer/data/aon_timer_testplan.hjson",
Guillermo Maturanad2c7fe62021-03-31 19:19:18 -0700105 "hw/ip/clkmgr/data/clkmgr_testplan.hjson",
Steve Nelsond677d782020-04-30 12:35:44 -0700106 "hw/ip/entropy_src/data/entropy_src_testplan.hjson",
Steve Nelson8cc9fc62020-12-08 08:00:45 -0800107 "hw/ip/csrng/data/csrng_testplan.hjson",
Eric Shiu5f1d3042021-03-17 17:24:11 -0700108 "hw/ip/adc_ctrl/data/adc_ctrl_testplan.hjson",
Steve Nelson8adade02020-12-17 13:40:35 -0800109 "hw/ip/edn/data/edn_testplan.hjson",
Srikrishna Iyerfb037392020-07-20 17:11:08 -0700110 "hw/ip/flash_ctrl/data/flash_ctrl_testplan.hjson",
Garret Kelly9eebde02019-10-22 15:36:49 -0400111 "hw/ip/gpio/data/gpio_testplan.hjson",
112 "hw/ip/hmac/data/hmac_testplan.hjson",
113 "hw/ip/i2c/data/i2c_testplan.hjson",
Timothy Chenc2e3f052020-09-10 18:47:25 -0700114 "hw/ip/keymgr/data/keymgr_testplan.hjson",
Cindy Chenb30114e2020-11-25 14:41:12 -0800115 "hw/ip/lc_ctrl/data/lc_ctrl_testplan.hjson",
Rupert Swarbrick7b247662021-03-19 13:15:28 +0000116 "hw/ip/otbn/data/otbn_testplan.hjson",
Cindy Chenda493592020-11-25 10:42:37 -0800117 "hw/ip/otp_ctrl/data/otp_ctrl_testplan.hjson",
Martin Lueker-Boden4d4acea2020-08-22 15:23:43 -0700118 "hw/ip/pattgen/data/pattgen_testplan.hjson",
Cindy Chendf135f02020-04-03 17:20:15 -0700119 "hw/ip/pinmux/data/pinmux_fpv_testplan.hjson",
Guillermo Maturana966df622021-05-13 09:28:52 -0700120 "hw/ip/pwm/data/pwm_testplan.hjson",
121 "hw/ip/pwrmgr/data/pwrmgr_testplan.hjson",
Tom Robertse856fb72021-05-12 15:19:31 +0100122 "hw/ip/rom_ctrl/data/rom_ctrl_testplan.hjson",
Guillermo Maturana0fd914d2021-07-01 15:02:17 -0700123 "hw/ip/rstmgr/data/rstmgr_testplan.hjson",
Cindy Chen9be86fe2019-11-02 11:42:18 -0700124 "hw/ip/rv_plic/data/rv_plic_fpv_testplan.hjson",
Garret Kelly9eebde02019-10-22 15:36:49 -0400125 "hw/ip/rv_timer/data/rv_timer_testplan.hjson",
Weicai Yangdda59482019-11-12 16:42:18 -0800126 "hw/ip/spi_device/data/spi_device_testplan.hjson",
Guillermo Maturana966df622021-05-13 09:28:52 -0700127 "hw/ip/spi_host/data/spi_host_testplan.hjson",
Srikrishna Iyere09bafc2021-03-08 21:56:25 -0800128 "hw/ip/sram_ctrl/data/sram_ctrl_base_testplan.hjson",
Guillermo Maturana966df622021-05-13 09:28:52 -0700129 "hw/ip/tlul/data/tlul_testplan.hjson",
Garret Kelly9eebde02019-10-22 15:36:49 -0400130 "hw/ip/uart/data/uart_testplan.hjson",
Srikrishna Iyer627f7822020-01-15 21:39:29 -0800131 "hw/ip/usbdev/data/usbdev_testplan.hjson",
Srikrishna Iyer5cddaf82020-04-24 14:19:49 -0700132 "hw/top_earlgrey/data/chip_testplan.hjson",
Timothy Chenf2d77262019-11-01 17:17:20 -0700133 "hw/top_earlgrey/data/standalone_sw_testplan.hjson",
Srikrishna Iyer86169d02021-05-10 09:35:52 -0700134 "util/dvsim/examples/testplanner/foo_testplan.hjson",
Garret Kelly9eebde02019-10-22 15:36:49 -0400135 ],
lowRISC Contributors802543a2019-08-31 12:12:56 +0100136
Eunchan Kim9790e3e2019-11-01 15:17:32 -0700137 # Pre-generated utility selfdoc
138 "selfdoc_tools": ["tlgen", "reggen"],
139
Sam Elliottb6745d32020-04-08 21:46:28 +0100140 # DIF Docs
141 "difs-directory": "sw/device/lib/dif",
142
lowRISC Contributors802543a2019-08-31 12:12:56 +0100143 # Output directory for documents
Garret Kelly9eebde02019-10-22 15:36:49 -0400144 "outdir":
145 SRCTREE_TOP.joinpath('build', 'docs'),
146 "outdir-generated":
147 SRCTREE_TOP.joinpath('build', 'docs-generated'),
148 "verbose":
149 False,
lowRISC Contributors802543a2019-08-31 12:12:56 +0100150}
151
152
Garret Kelly9eebde02019-10-22 15:36:49 -0400153def generate_dashboards():
Philipp Wagner8171ede2021-03-15 21:47:01 +0000154 for dashboard_name, dirs in config["dashboard_definitions"].items():
Garret Kelly9eebde02019-10-22 15:36:49 -0400155 hjson_paths = []
Philipp Wagner8171ede2021-03-15 21:47:01 +0000156 for d in dirs:
157 hjson_paths += SRCTREE_TOP.joinpath(d).rglob('*.prj.hjson')
158
159 hjson_paths.sort(key=lambda f: f.name)
Garret Kelly9eebde02019-10-22 15:36:49 -0400160
161 dashboard_path = config["outdir-generated"].joinpath(
Philipp Wagner8171ede2021-03-15 21:47:01 +0000162 dashboard_name, 'dashboard')
163 dashboard_path.parent.mkdir(exist_ok=True, parents=True)
Philipp Wagner57df62c2019-11-04 14:49:24 +0000164 dashboard_html = open(str(dashboard_path), mode='w')
Garret Kelly9eebde02019-10-22 15:36:49 -0400165 for hjson_path in hjson_paths:
166 gen_dashboard_entry.gen_dashboard_html(hjson_path, dashboard_html)
167 dashboard_html.close()
lowRISC Contributors802543a2019-08-31 12:12:56 +0100168
169
Garret Kelly9eebde02019-10-22 15:36:49 -0400170def generate_hardware_blocks():
171 for hardware in config["hardware_definitions"]:
Rupert Swarbrick269bb3d2021-02-23 15:41:56 +0000172 regs = IpBlock.from_path(str(SRCTREE_TOP.joinpath(hardware)), [])
Garret Kelly9eebde02019-10-22 15:36:49 -0400173
Rupert Swarbrick269bb3d2021-02-23 15:41:56 +0000174 hw_path = config["outdir-generated"].joinpath(hardware)
175 dst_path = hw_path.parent
176 dst_path.mkdir(parents=True, exist_ok=True)
Garret Kelly9eebde02019-10-22 15:36:49 -0400177
Rupert Swarbrick269bb3d2021-02-23 15:41:56 +0000178 regs_path = dst_path.joinpath(hw_path.name + '.registers')
179 with open(regs_path, 'w') as regs_file:
180 gen_html.gen_html(regs, regs_file)
Garret Kelly9eebde02019-10-22 15:36:49 -0400181
Rupert Swarbrick269bb3d2021-02-23 15:41:56 +0000182 hwcfg_path = dst_path.joinpath(hw_path.name + '.hwcfg')
183 with open(hwcfg_path, 'w') as hwcfg_file:
184 gen_cfg_html.gen_cfg_html(regs, hwcfg_file)
lowRISC Contributors802543a2019-08-31 12:12:56 +0100185
186
Garret Kelly9eebde02019-10-22 15:36:49 -0400187def generate_testplans():
188 for testplan in config["testplan_definitions"]:
Srikrishna Iyer86169d02021-05-10 09:35:52 -0700189 plan = Testplan.Testplan(SRCTREE_TOP.joinpath(testplan),
190 repo_top=SRCTREE_TOP)
Garret Kelly9eebde02019-10-22 15:36:49 -0400191 plan_path = config["outdir-generated"].joinpath(testplan + '.testplan')
192 plan_path.parent.mkdir(parents=True, exist_ok=True)
193
Philipp Wagner57df62c2019-11-04 14:49:24 +0000194 testplan_html = open(str(plan_path), mode='w')
Srikrishna Iyer86169d02021-05-10 09:35:52 -0700195 testplan_html.write(plan.get_testplan_table("html"))
Garret Kelly9eebde02019-10-22 15:36:49 -0400196 testplan_html.close()
lowRISC Contributors802543a2019-08-31 12:12:56 +0100197
198
Eunchan Kim9790e3e2019-11-01 15:17:32 -0700199def generate_selfdocs():
200 """Generate documents for the tools in `util/` if `--doc` option exists.
201
202 Each tool creates selfdoc differently. Manually invoked.
203 """
204 for tool in config["selfdoc_tools"]:
205 selfdoc_path = config["outdir-generated"].joinpath(tool + '.selfdoc')
206 selfdoc_path.parent.mkdir(parents=True, exist_ok=True)
Philipp Wagner57df62c2019-11-04 14:49:24 +0000207 with open(str(selfdoc_path), mode='w') as fout:
Eunchan Kim9790e3e2019-11-01 15:17:32 -0700208 if tool == "reggen":
209 reggen_selfdoc.document(fout)
210 elif tool == "tlgen":
211 fout.write(tlgen.selfdoc(heading=3, cmd='tlgen.py --doc'))
212
Tobias Wölfelff543342020-05-14 16:14:56 +0200213
Pirmin Vogel3ff52be2021-01-20 18:20:25 +0100214def generate_pkg_reqs():
215 """Generate an apt/yum command line invocation from
216 apt/yum-requirements.txt
Sam Elliott692078c2020-02-07 17:23:21 +0000217
Pirmin Vogel3ff52be2021-01-20 18:20:25 +0100218 This will be saved in outdir-generated/apt_cmd.txt and
219 outdir-generated/yum_cmd.txt, respectively.
Sam Elliott692078c2020-02-07 17:23:21 +0000220 """
Sam Elliott692078c2020-02-07 17:23:21 +0000221
Pirmin Vogel3ff52be2021-01-20 18:20:25 +0100222 for pkgmgr in ["apt", "yum"]:
223 # Read the apt/yum-requirements.txt
224 requirements = []
225 requirements_file = open(str(SRCTREE_TOP.joinpath(pkgmgr + "-requirements.txt")))
226 for package_line in requirements_file.readlines():
227 # Ignore everything after `#` on each line, and strip whitespace
228 package = package_line.split('#', 1)[0].strip()
229 if package:
230 # only add non-empty lines to packages
231 requirements.append(package)
232
233 cmd = "$ sudo " + pkgmgr + " install " + " ".join(requirements)
234 cmd_lines = textwrap.wrap(cmd,
Sam Elliott692078c2020-02-07 17:23:21 +0000235 width=78,
236 replace_whitespace=True,
237 subsequent_indent=' ')
Pirmin Vogel3ff52be2021-01-20 18:20:25 +0100238 # Newlines need to be escaped
239 cmd = " \\\n".join(cmd_lines)
Sam Elliott692078c2020-02-07 17:23:21 +0000240
Pirmin Vogel3ff52be2021-01-20 18:20:25 +0100241 # And then to write the generated string directly to the file.
242 cmd_path = config["outdir-generated"].joinpath(pkgmgr + '_cmd.txt')
243 cmd_path.parent.mkdir(parents=True, exist_ok=True)
244 with open(str(cmd_path), mode='w') as fout:
245 fout.write(cmd)
Sam Elliott692078c2020-02-07 17:23:21 +0000246
Tobias Wölfelff543342020-05-14 16:14:56 +0200247
Pirmin Vogel0761f1c2020-03-09 17:47:45 +0100248def generate_tool_versions():
249 """Generate an tool version number requirement from tool_requirements.py
250
251 The version number per tool will be saved in outdir-generated/version_$TOOL_NAME.txt
252 """
253
Pirmin Vogel0761f1c2020-03-09 17:47:45 +0100254 # And then write a version file for every tool.
Rupert Swarbrick9ab407e2021-01-25 11:40:17 +0000255 for tool, req in TOOL_REQUIREMENTS.items():
Pirmin Vogel0761f1c2020-03-09 17:47:45 +0100256 version_path = config["outdir-generated"].joinpath('version_' + tool + '.txt')
257 version_path.parent.mkdir(parents=True, exist_ok=True)
258 with open(str(version_path), mode='w') as fout:
Rupert Swarbrick9ab407e2021-01-25 11:40:17 +0000259 fout.write(req.min_version)
Pirmin Vogel0761f1c2020-03-09 17:47:45 +0100260
Eunchan Kim4096f7d2020-10-20 17:55:47 -0700261
Sam Elliottb6745d32020-04-08 21:46:28 +0100262def generate_dif_docs():
263 """Generate doxygen documentation and DIF listings from DIF source comments.
264
265 This invokes Doxygen, and a few other things. Be careful of changing any
266 paths here, some correspond to paths in other configuration files.
267 """
268
269 logging.info("Generating Software API Documentation (Doxygen)...")
270
271 doxygen_out_path = config["outdir-generated"].joinpath("sw")
272
273 # The next two paths correspond to relative paths specified in the Doxyfile
274 doxygen_xml_path = doxygen_out_path.joinpath("api-xml")
275
276 # We need to prepare this path because doxygen won't `mkdir -p`
277 doxygen_sw_path = doxygen_out_path.joinpath("public-api/sw/apis")
278 doxygen_sw_path.mkdir(parents=True, exist_ok=True)
279
Sam Elliottc8fa5582020-04-08 21:02:05 +0100280 # This is where warnings will be generated
281 doxygen_warnings_path = doxygen_out_path.joinpath("doxygen_warnings.log")
282 if doxygen_warnings_path.exists():
283 doxygen_warnings_path.unlink()
284
Sam Elliottb6745d32020-04-08 21:46:28 +0100285 doxygen_args = [
286 "doxygen",
287 str(SRCTREE_TOP.joinpath("util/doxygen/Doxyfile")),
288 ]
289
Eunchan Kim4096f7d2020-10-20 17:55:47 -0700290 doxygen_results = subprocess.run( # noqa: F841
291 doxygen_args, check=True,
Sam Elliottb6745d32020-04-08 21:46:28 +0100292 cwd=str(SRCTREE_TOP), stdout=subprocess.PIPE,
Eunchan Kim4096f7d2020-10-20 17:55:47 -0700293 env=dict(
294 os.environ,
Sam Elliottb6745d32020-04-08 21:46:28 +0100295 SRCTREE_TOP=str(SRCTREE_TOP),
296 DOXYGEN_OUT=str(doxygen_out_path),
297 ))
298
299 logging.info("Generated Software API Documentation (Doxygen)")
300
Sam Elliottc8fa5582020-04-08 21:02:05 +0100301 if doxygen_warnings_path.exists():
Eunchan Kim4096f7d2020-10-20 17:55:47 -0700302 logging.warning("Doxygen Generated Warnings "
303 "(saved in {})".format(str(doxygen_warnings_path)))
Sam Elliottc8fa5582020-04-08 21:02:05 +0100304
Sam Elliottb6745d32020-04-08 21:46:28 +0100305 combined_xml = gen_dif_listing.get_combined_xml(doxygen_xml_path)
306
307 dif_paths = []
308 dif_paths.extend(sorted(SRCTREE_TOP.joinpath(config["difs-directory"]).glob("dif_*.h")))
309
310 dif_listings_root_path = config["outdir-generated"].joinpath("sw/difs_listings")
311 difrefs_root_path = config["outdir-generated"].joinpath("sw/difref")
312
313 for dif_header_path in dif_paths:
314 dif_header = str(dif_header_path.relative_to(SRCTREE_TOP))
315
316 dif_listings_filename = dif_listings_root_path.joinpath(dif_header + ".html")
317 dif_listings_filename.parent.mkdir(parents=True, exist_ok=True)
318
Sam Elliott24398ab2020-07-17 17:02:05 +0100319 with open(str(dif_listings_filename), mode='w') as dif_listings_html:
320 gen_dif_listing.gen_listing_html(combined_xml, dif_header,
321 dif_listings_html)
Sam Elliottb6745d32020-04-08 21:46:28 +0100322
323 difref_functions = gen_dif_listing.get_difref_info(combined_xml, dif_header)
324 for function in difref_functions:
325 difref_filename = difrefs_root_path.joinpath(function["name"] + '.html')
326 difref_filename.parent.mkdir(parents=True, exist_ok=True)
327
Sam Elliott24398ab2020-07-17 17:02:05 +0100328 with open(str(difref_filename), mode='w') as difref_html:
329 gen_dif_listing.gen_difref_html(function, difref_html)
Sam Elliottb6745d32020-04-08 21:46:28 +0100330
331 logging.info("Generated DIF Listing for {}".format(dif_header))
332
Eunchan Kim9790e3e2019-11-01 15:17:32 -0700333
Rupert Swarbrick63da48e2020-07-08 10:16:57 +0100334def generate_otbn_isa():
335 '''Generate the OTBN ISA documentation fragment
336
337 The result is in Markdown format and is written to
338 outdir-generated/otbn-isa.md
339
340 '''
341 otbn_dir = SRCTREE_TOP / 'hw/ip/otbn'
342 script = otbn_dir / 'util/yaml_to_doc.py'
343 yaml_file = otbn_dir / 'data/insns.yml'
Rupert Swarbrick4077bec2020-10-05 11:50:11 +0100344 impl_file = otbn_dir / 'dv/otbnsim/sim/insn.py'
Rupert Swarbrick63da48e2020-07-08 10:16:57 +0100345
Rupert Swarbrickd3de4bb2020-09-01 17:50:19 +0100346 out_dir = config['outdir-generated'].joinpath('otbn-isa')
Rupert Swarbrick4077bec2020-10-05 11:50:11 +0100347 subprocess.run([str(script), str(yaml_file), str(impl_file), str(out_dir)],
348 check=True)
Rupert Swarbrick63da48e2020-07-08 10:16:57 +0100349
350
Tobias Wölfel19a86e22020-05-14 14:31:00 +0200351def hugo_match_version(hugo_bin_path, version):
352 logging.info("Hugo binary path: %s", hugo_bin_path)
353 args = [str(hugo_bin_path), "version"]
Silvestrs Timofejevsecaf87c2019-11-12 21:52:57 +0000354 process = subprocess.run(args,
355 universal_newlines=True,
356 stdout=subprocess.PIPE,
357 check=True,
358 cwd=str(SRCTREE_TOP))
359
Tobias Wölfel19a86e22020-05-14 14:31:00 +0200360 logging.info("Checking for correct Hugo version: %s", version)
Silvestrs Timofejevsecaf87c2019-11-12 21:52:57 +0000361 # Hugo version string example:
Tobias Wölfelff543342020-05-14 16:14:56 +0200362 # "Hugo Static Site Generator v0.59.0-1DD0C69C/extended linux/amd64 BuildDate: 2019-10-21T09:45:38Z" # noqa: E501
Rupert Swarbrick4dcb0742021-04-28 14:54:17 +0100363 return bool(re.search("v" + version + ".*[/+]extended", process.stdout))
Silvestrs Timofejevsecaf87c2019-11-12 21:52:57 +0000364
365
Philipp Wagnercd57f862019-10-31 14:20:39 +0000366def install_hugo(install_dir):
367 """Download and "install" hugo into |install_dir|
368
369 install_dir is created if it doesn't exist yet.
370
371 Limitations:
Sam Elliott1087d272020-11-17 18:56:19 +0000372 Currently only 64-bit x86 Linux and macOS is supported."""
Philipp Wagnercd57f862019-10-31 14:20:39 +0000373
374 # TODO: Support more configurations
Sam Elliott1087d272020-11-17 18:56:19 +0000375 if platform.system() == 'Linux' and platform.machine() == 'x86_64':
376 download_url = ('https://github.com/gohugoio/hugo/releases/download/v{version}'
Timothy Chen7df14342021-03-23 17:05:38 -0700377 '/hugo_extended_{version}_Linux-64bit.tar.gz').format(
378 version=HUGO_EXTENDED_VERSION)
Philipp Wagnercd57f862019-10-31 14:20:39 +0000379
Sam Elliott1087d272020-11-17 18:56:19 +0000380 elif platform.system() == 'Darwin' and platform.machine() == 'x86_64':
Timothy Chen7df14342021-03-23 17:05:38 -0700381 download_url = ('https://github.com/gohugoio/hugo/releases/download/v{version}'
382 '/hugo_extended_{version}_macOS-64bit.tar.gz').format(
383 version=HUGO_EXTENDED_VERSION)
Sam Elliott1087d272020-11-17 18:56:19 +0000384
385 else:
386 logging.fatal(
387 "Auto-install of hugo only supported for 64-bit x86 Linux and "
388 "macOS. Manually install hugo and re-run this script with --force-global.")
389 return False
390
Philipp Wagnercd57f862019-10-31 14:20:39 +0000391 install_dir.mkdir(exist_ok=True, parents=True)
392 hugo_bin_path = install_dir / 'hugo'
393
Tobias Wölfel19a86e22020-05-14 14:31:00 +0200394 try:
395 if hugo_match_version(hugo_bin_path, HUGO_EXTENDED_VERSION):
396 return hugo_bin_path
Tobias Wölfelff543342020-05-14 16:14:56 +0200397 except PermissionError:
Tobias Wölfel19a86e22020-05-14 14:31:00 +0200398 # If there is an error checking the version just continue to download
Tobias Wölfelff543342020-05-14 16:14:56 +0200399 logging.info("Hugo version could not be verified. Continue to download.")
400 except FileNotFoundError:
Tobias Wölfel19a86e22020-05-14 14:31:00 +0200401 pass
402
Philipp Wagnercd57f862019-10-31 14:20:39 +0000403 # TODO: Investigate the use of Python builtins for downloading. Extracting
404 # the archive will probably will be a call to tar.
Sam Elliott1087d272020-11-17 18:56:19 +0000405 cmd = 'curl -sL {download_url} | tar -xzO hugo > {hugo_bin_file}'.format(
Philipp Wagnercd57f862019-10-31 14:20:39 +0000406 hugo_bin_file=str(hugo_bin_path), download_url=download_url)
407 logging.info("Calling %s to download hugo.", cmd)
Philipp Wagner57df62c2019-11-04 14:49:24 +0000408 subprocess.run(cmd, shell=True, check=True, cwd=str(SRCTREE_TOP))
Philipp Wagnercd57f862019-10-31 14:20:39 +0000409 hugo_bin_path.chmod(0o755)
Tobias Wölfel19a86e22020-05-14 14:31:00 +0200410 return hugo_bin_path
Philipp Wagnercd57f862019-10-31 14:20:39 +0000411
412
Martin Lueker-Bodendcd6c682021-05-16 21:20:10 -0700413def invoke_hugo(preview, bind_wan, hugo_opts, hugo_bin_path):
Garret Kelly9eebde02019-10-22 15:36:49 -0400414 site_docs = SRCTREE_TOP.joinpath('site', 'docs')
415 config_file = str(site_docs.joinpath('config.toml'))
416 layout_dir = str(site_docs.joinpath('layouts'))
417 args = [
Tobias Wölfel19a86e22020-05-14 14:31:00 +0200418 str(hugo_bin_path),
Garret Kelly9eebde02019-10-22 15:36:49 -0400419 "--config",
420 config_file,
421 "--destination",
422 str(config["outdir"]),
423 "--contentDir",
424 str(SRCTREE_TOP),
425 "--layoutDir",
426 layout_dir,
427 ]
428 if preview:
429 args += ["server"]
Martin Lueker-Bodendcd6c682021-05-16 21:20:10 -0700430 # --bind-wan only applies when previewing.
431 if bind_wan:
Guillermo Maturana0fd914d2021-07-01 15:02:17 -0700432 args += ["--bind", "0.0.0.0", "--baseURL",
433 "http://" + socket.getfqdn()]
434 if hugo_opts is not None:
Martin Lueker-Bodendcd6c682021-05-16 21:20:10 -0700435 args += hugo_opts
436
Philipp Wagner57df62c2019-11-04 14:49:24 +0000437 subprocess.run(args, check=True, cwd=str(SRCTREE_TOP))
lowRISC Contributors802543a2019-08-31 12:12:56 +0100438
439
440def main():
441 logging.basicConfig(level=logging.INFO,
442 format="%(asctime)s - %(message)s",
443 datefmt="%Y-%m-%d %H:%M")
444
445 parser = argparse.ArgumentParser(
446 prog="build_docs",
447 formatter_class=argparse.RawDescriptionHelpFormatter,
448 usage=USAGE)
449 parser.add_argument(
450 '--preview',
451 action='store_true',
Tobias Wölfelff543342020-05-14 16:14:56 +0200452 help="""Starts a local server with live reload (updates triggered upon
453 changes in the documentation files). This feature is intended
lowRISC Contributors802543a2019-08-31 12:12:56 +0100454 to preview the documentation locally.""")
Tobias Wölfel19a86e22020-05-14 14:31:00 +0200455 parser.add_argument(
Martin Lueker-Bodendcd6c682021-05-16 21:20:10 -0700456 '--bind-wan',
457 action='store_true',
458 help="""When previewing, bind to all interfaces (instead of just
459 localhost). This makes the documentation preview visible from
460 other hosts.""")
461 parser.add_argument(
Tobias Wölfel19a86e22020-05-14 14:31:00 +0200462 '--force-global',
463 action='store_true',
464 help="""Use a global installation of Hugo. This skips the version
465 check and relies on Hugo to be available from the environment.""")
Martin Lueker-Bodendcd6c682021-05-16 21:20:10 -0700466 parser.add_argument(
467 '--hugo-opts',
468 nargs=argparse.REMAINDER,
469 help="""Indicates that all following arguments should be passed as
470 additional options to hugo. This may be useful for controlling
471 server bindings and so forth.""")
Garret Kelly9eebde02019-10-22 15:36:49 -0400472 parser.add_argument('--hugo', help="""TODO""")
lowRISC Contributors802543a2019-08-31 12:12:56 +0100473
474 args = parser.parse_args()
475
Garret Kelly9eebde02019-10-22 15:36:49 -0400476 generate_hardware_blocks()
477 generate_dashboards()
478 generate_testplans()
Eunchan Kim9790e3e2019-11-01 15:17:32 -0700479 generate_selfdocs()
Pirmin Vogel3ff52be2021-01-20 18:20:25 +0100480 generate_pkg_reqs()
Pirmin Vogel0761f1c2020-03-09 17:47:45 +0100481 generate_tool_versions()
Sam Elliottb6745d32020-04-08 21:46:28 +0100482 generate_dif_docs()
Rupert Swarbrick63da48e2020-07-08 10:16:57 +0100483 generate_otbn_isa()
Philipp Wagnercd57f862019-10-31 14:20:39 +0000484
485 hugo_localinstall_dir = SRCTREE_TOP / 'build' / 'docs-hugo'
486 os.environ["PATH"] += os.pathsep + str(hugo_localinstall_dir)
487
Tobias Wölfel19a86e22020-05-14 14:31:00 +0200488 hugo_bin_path = "hugo"
489 if not args.force_global:
490 try:
491 hugo_bin_path = install_hugo(hugo_localinstall_dir)
492 except KeyboardInterrupt:
493 pass
Silvestrs Timofejevsecaf87c2019-11-12 21:52:57 +0000494
Tobias Wölfel19a86e22020-05-14 14:31:00 +0200495 try:
Martin Lueker-Bodendcd6c682021-05-16 21:20:10 -0700496 invoke_hugo(args.preview, args.bind_wan, args.hugo_opts, hugo_bin_path)
Tobias Wölfel19a86e22020-05-14 14:31:00 +0200497 except subprocess.CalledProcessError:
498 sys.exit("Error building site")
499 except PermissionError:
500 sys.exit("Error running Hugo")
Philipp Wagnere08be112019-10-31 14:43:52 +0000501 except KeyboardInterrupt:
502 pass
lowRISC Contributors802543a2019-08-31 12:12:56 +0100503
504
lowRISC Contributors802543a2019-08-31 12:12:56 +0100505if __name__ == "__main__":
506 main()