Documentation generation#
Automatic documentation generation of hardware designs is one of the main purposes of having a machine-readable project description format along with a library providing a Document Object Model (DOM). Some of the features to be implemented on top of pyVHDLModelUtils are the following:
Entity symbol:
Single page HTML/reStructuredText/markdown body (see TerosHDL CLI examples).
Sphinx project/domain with cross-references (placeholder: gh:Paebbels/sphinxcontrib-vhdldomain).
Diagrams:
For Sphinx (see Integration with Sphinx » Diagrams).
For asciidoctor (see Asciidoctor Diagram).
Integration with Sphinx#
Sphinx is the de facto static site generator (SSG) used for building documentation of Python projects. It was originally created for Python, and it has support for documenting software projects in several languages. Since many open source EDA projects and CLIs are written in Python, Sphinx is probably the most used SSG. It’s used by SymbiFlow, GHDL, VUnit, pyVHDLModel/pyVHDLParser, cocotb, TerosHDL, Boolector, edalize/fusesoc, Wishbone (FOSSi), SpinalHDL, tsfpga…
Additional features can be added to Sphinx through extensions. For instance, intersphinx allows cross-referencing content across sites, as if they were local references. That is really handy for building knowledge as a community.
The default plaintext markup language used by Sphinx is reStructuredText. Other markup languages, such as Markdown, can be imported through extensions, however, not all cross-reference features are available when using those.
Overall, there are four approaches for adding content with custom processing to a site built with Sphinx:
Execute before Sphinx:
html_static_path: content in the static paths is copied to the output’s _static directory, overriding existing sources with the same name. This is typically used for adding images and/or customising the CSS.
html_extra_path: content in extra paths is copied as-is to the output directory, overriding existing sources with the same name. This can be used for adding static content generated with a different generator.
Built into Sphinx:
exec: a generic directive (such as the ones proposed in stackoverflow.com/a/18143318) allows executing arbitrary Python code which generates reStructuredText output through print statements.
Ad-hoc directive: as explained in Developing extensions for Sphinx, there are several objects whose API can be used when writing extensions: Application, Environment, Builder and Config. Those allow fine-grained integration into Sphinx’s internals, potentially bypassing the reStructuredText parsing layer. This is the end-goal for tightly integrated and customised functionality.
exec directive#
The generic exec extension (see doc/exec.py) is based on stackoverflow.com/a/18143318. It allows executing arbitrary Python code which prints reStructuredText output.
Setup is done by adding exec to the extensions variable of the conf.py
.
Depending on the location of exec.py, it might be necessary to add sys.path.insert(0, abspath("."))
.
Other than that, users (developers of the arbitrary Python code) don’t need to know internals of Sphinx, but just print
regular reStructuredText statements.
However, a main caveat of the current implementation is that Sphinx will never fail. That is, even if the arbitrary code fails, the Sphinx build is reported as successful. That’s because errors are shown as an admonition instead of making the build fail. As a result, manual inspection of the output is required (desirable).
Moreover, currently no context is passed to the Python code. Therefore, it is not possible to know where it belongs in the hierarchy of the document. This is a limitation for generating headers and other context dependent statements.
Note
Should you want to help improve the implementation of this directive, let us know!
Lists and tables#
This section showcases a naive approach for documenting VHDL design units using pyGHDL.dom.
It is based on exec directive and the sphinx
module of pyVHDLModelUtils.
First, initDesign needs to be executed, in order to provide the lists of sources and VHDL library names.
Note
Currently, there is no specific JSON/YAML format supported for this task. Find work in progress in section Core.
.. exec::
from pyVHDLModelUtils.sphinx import initDesign
initDesign(
'..',
AXI4 = ["AXI4Stream/src/*.vhd"],
fpconv = ["fpconv/*.vhd"]
)
The output of initDesign is a NOTE containing the result of parsing the sources with pyGHDL.dom. If a failure was produced, an admonition of type ERROR is shown instead.
Note
Output of initDesign:
AXI4
AXI4Stream/src/fifo.vhd
[NOT IMPLEMENTED] Array_Subtype_Definition
AXI4Stream/src/axis_buffer.vhd
fpconv
fpconv/tb.vhd
Then, printDocumentationOf allows generating the documentation of libraries and/or design units. By default, the content is shown where the directive was called. In case of failure, an admonition of type ERROR is shown.
.. exec::
from pyVHDLModelUtils.sphinx import printDocumentationOf
printDocumentationOf()
Design content:
Library AXI4 [2 entities]
Entity: fifo
Architecture: arch
Entity: axis_buffer
Architecture: arch
At the moment, two different styles are supported for printing the documentation of entities.
List style:
.. exec::
from pyVHDLModelUtils.sphinx import printDocumentationOf
printDocumentationOf(["AXI4.axis_buffer"])
Entity axis_buffer from Library AXI4:
Generics:
data_width :
integer
:=32
fifo_depth :
integer
:=0
Ports:
s_axis_clk : in
std_logic
s_axis_rstn : in
std_logic
s_axis_rdy : out
std_logic
s_axis_data : in
std_logic_vector(data_width - 1 downto 0)
s_axis_valid : in
std_logic
s_axis_strb : in
std_logic_vector((data_width / 8) - 1 downto 0)
s_axis_last : in
std_logic
m_axis_clk : in
std_logic
m_axis_rstn : in
std_logic
m_axis_valid : out
std_logic
m_axis_data : out
std_logic_vector(data_width - 1 downto 0)
m_axis_rdy : in
std_logic
m_axis_strb : out
std_logic_vector((data_width / 8) - 1 downto 0)
m_axis_last : out
std_logic
Architectures:
arch
Table style:
.. exec::
from pyVHDLModelUtils.sphinx import printDocumentationOf
printDocumentationOf(
["AXI4.axis_buffer"],
'rst:table'
)
Identifiers |
Type |
Default |
---|---|---|
data_width |
|
|
fifo_depth |
|
|
Identifiers |
Mode |
Type |
Default |
---|---|---|---|
s_axis_clk |
in |
|
|
s_axis_rstn |
in |
|
|
s_axis_rdy |
out |
|
|
s_axis_data |
in |
|
|
s_axis_valid |
in |
|
|
s_axis_strb |
in |
|
|
s_axis_last |
in |
|
|
m_axis_clk |
in |
|
|
m_axis_rstn |
in |
|
|
m_axis_valid |
out |
|
|
m_axis_data |
out |
|
|
m_axis_rdy |
in |
|
|
m_axis_strb |
out |
|
|
m_axis_last |
out |
|
Identifier |
Number of statements |
---|---|
arch |
11 |
Note
This is a demo for showcasing the capabilities of pyGHDL.dom and pyVHDLModel. Should you want to help improve the implementation for it to be more usable in practice, let us know!
VHDL Domain#
gh:Paebbels/sphinxcontrib-vhdldomain is work in progress for adding a VHDL language domain to Sphinx. That is, a set of nestable directives resembling the architecture of pyVHDLModel. The purpose is twofold:
Allow a better integration of the content into Sphinx, rather than generating reStructuredText output from arbitrary Python functions.
Allow users to specify a pyVHDLModel project by handwriting directives in reStructuredText sources, by either pointing to individual files or explicitly describing all the items.
See Paebbels/sphinxcontrib-vhdldomain#4.
There is also gh:CESNET/sphinx-vhdl, which uses a custom basic parser (CESNET/sphinx-vhdl: src/sphinxvhdl/autodoc.py) and multiple custom Sphinx directives (CESNET/sphinx-vhdl: src/sphinxvhdl/vhdl.py).
Diagrams#
Both GHDL and Yosys allow generating diagrams of synthesised designs.
ghdl synth --out=dot
generates a Graphviz DOT diagram of the netlist AST.gh:ghdl/ghdl-yosys-plugin allows using GHDL as a frontend for Yosys.
As explained in ghdl.github.io/ghdl/synthesis » Yosys plugin, ghdl-yosys-plugin and Yosys allow converting VHDL to EDIT, SMT, BTOR2, FIRRTL, etc.
Yosys’s show command allows generating a Graphviz DOT diagram and compiling it to a graphics file (say SVG).
Optionally, command aigmap can map the logic to and/nand gates only, before generating the diagram.
Alternatively, gh:nturley/netlistsvg allows generating SVG schematics from Yosys’ JSON netlist output.
By combining those tools, diagrams of a given VHDL design can be generated as follows:
~# yosys -p 'ghdl --std=08 design.vhd -e primary_unit secondary_unit; prep; write_json netlist.json'
~# netlistsvg netlist.json -o netlist.svg
~# convert netlist.svg netlist.png
Important
There is an Sphinx extension named sphinxcontrib-hdl-diagrams, which wraps Yosys and (optionally) netlistsvg in a directive. That allows including diagrams in the docs without manually calling yosys and netlistsvg. For instance:
.. hdl-diagram:: file.v
:type: netlistsvg
:module: name
:flatten:
However, since sphinxcontrib-hdl-diagrams depends on combining the WASM version of Yosys and netlistsvg (which is JavaScript), it does not support VHDL yet. There is work in progress for using the extension with “natively” installed tools, as well as supporting VHDL and mixed-language designs. See SymbiFlow/sphinxcontrib-hdl-diagrams#65, SymbiFlow/sphinxcontrib-hdl-diagrams#72 and SymbiFlow/sphinxcontrib-hdl-diagrams#73.