Documentation guidelines

A brief set-of-rules for the documentation.

Note

The old wiki uses dokuwiki. When importing text from there, consider the automated options that are provided in this page to convert it to reST.

Indentation

Directives are indented with 3 space, which is Sphinx’s default. At code directives, the code keeps its original indentation (e.g. 2 spaces for Verilog code), but is offset by 3 spaces at the beginning of every line, to instruct Sphinx the beginning and end of the code directive.

Table of contents

The relation between pages are created with the toctree directive, which allows to generate the table of contents and navigation bars.

Each page may have only one toctree, since they are the equivalent of the volumes of a book, and it does not make sense to have multiple “volumes” at the repository level.

The only exception is the ADI System Level Documentation repository, which indeed contains various types of documentation (eval-boards, university program, Linux drivers, etc.); and it uses the topic field at lut.py to keep track of each.

The toctree directive has the following format:

.. toctree::
   :maxdepth: <depth>

   Custom title <path/to/page>

For pages with shorter titles, such as libraries, the label is inherited from the page itself, for example:

.. toctree::

   library/axi_dmac/index
   library/spi_engine/index

And for pages with long titles, such as projects, overwrite the full title with a custom title, e.g:

.. toctree::

   AD7616-SDZ <projects/ad7616_sdz/index>

This way, only “AD7616-SDZ” will be displayed in the page navigation bar instead of “AD7616-SDZ HDL project”.

Also, it is recommended to wrap the toctree in a “Contents” section:

Contents
========

.. toctree::

   some_page

Versioning

To avoid having the version set in multiple places or having to tweak conf.py to obtain it from somewhere else, continuous integration can set the environment variable ADOC_DOC_VERSION to set the version value.

Still, the version value on conf.py has higher precedence, and ADOC_DOC_VERSION will be ignored if the variable is already set.

The CI, in general, should set ADOC_DOC_VERSION as the current checkout branch in the pipeline (e.g. main, v1.0.0).

Tip

If creating a branch or PR output, consider using GitHub short reference ${{ github.ref_name }}.

If both environment variable and version on conf.py are unset, it defaults to an empty string.

Also, set ADOC_TARGET_DEPTH to match the final destination depth, for example, if the target directory is:

  • ./: 0 or unset

  • ./v2.2: 1

  • ./prs/1234: 2

  • ./staging/user/branch: 3

References

References have the format library/project context, e.g. :ref:`vivado block-diagrams` renders as Vivado block-diagrams. Notice how neither library nor project are present in the label, since there is no naming collision between libraries or projects (no project will ever be named axi_dmac).

Also, for project, libraries and IPs, the names should be exactly the name of its folders, e.g. axi_pwm_gen and not axi-pwm-gen or AXI_PWM_GEN, this helps avoid broken references.

Attention

Do not break reference role between lines! Even though Sphinx allows breaking line inside the reference role, it makes pattern matching really hard.

For resources without a particular source code file/folder, prefer hyphen - separation, for example, spi_engine control-interface instead of spi_engine control_interface.

In organization references

For references to Sphinx docs inside the organization (repos listed in the repotoc), the ref role is extended with the syntax :ref-<external>:`label` where external is a mapped source, for example, :ref-hdl:`spi_engine control-interface`. It is also possible to customize the text, e.g. :ref-hdl:`Custom text <spi_engine control-interface>`.

A warning is thrown when a reference is not found.

Repository mappings are enabled to the conf.py file with the following format:

interref_repos = [external...]

For example:

interref_repos = ['hdl', 'no-OS', 'pyadi-iio/main']

Notice that in the example main suffixes pyadi-iio, this means that will look for the build at path main of this repo instead of at root. This can be used to target a specific version, if the target repository stores multiple, for example, v1.1, more about that Versioned.

Resolved the path, the mappings are obtained from the InterSphinx mapping file.

To show all links of an InterSphinx mapping file, use the built-in tool:

python3 -m sphinx.ext.intersphinx https://analogdevicesinc.github.io/hdl/objects.inv

The previous syntax applies only for references/label links (domain ref/label), for every other domain, set it explicitly, e.g. :ref-hdl:doc:`user_guide/docs_guidelines`. The domains are also listed in the sphinx.ext.intersphinx output.

Others options:

  • ADOC_INTERREF_URI: uri for the inventory and links, default is https://analogdevicesinc.github.io/; it can be set to a local path, e.g. ../../.

Outside organization Sphinx references

To create references to other Sphinx documentations, sphinx.ext.intersphinx can be added to the conf.py extension list. The syntax is :external+<external>:<domain>:`label`, where external is a mapped source and the domain is the reference type, for example, :external+sphinx:doc:`development/theming`. It is also possible to customize the text, e.g. :external+sphinx:ref:`Custom text <examples>`.

A warning is thrown when a reference is not found.

Mappings are included to the conf.py file with the following format:

intersphinx_mapping = {
    '<name>': ('<path/to/external>', None)
}

For example:

intersphinx_mapping = {
    'sphinx': ('https://www.sphinx-doc.org/en/master', None)
}

And new mappings can be included as needed.

To show all links of an InterSphinx mapping file, use the built-in tool:

python3 -m sphinx.ext.intersphinx https://www.sphinx-doc.org/en/master/objects.inv

Text width

Each line must be less than 80 columns wide. You can use the fold command to break the lines of the imported text while respecting word-breaks:

cat imported.txt | fold -sw 80 > imported.rst

Or use pandoc:

pandoc imported.txt -f dokuwiki -t rst --columns=80 -s -o imported.rst

Tables

Prefer list-tables and imported csv-tables (using the file option), because they are faster to create, easier to maintain and the 80 column-width rule can be respected with list-tables.

You can use the following command:

pandoc imported.txt -f dokuwiki -t rst --columns=80 -s -o imported.rst --list-tables

The list-tables parameter requires pandoc-types >= 1.23, included in any recent pandoc release; if it is not an option, you shall remove it and export in the grid table format.

Now you only have to adjust the widths and give the final touches, like using the correct directives and roles.

Lists

Unordered lists use * or - and ordered lists #..

Child items must be aligned with the first letter of the parent item, that means, 2 spaces for unordered list and 3 spaces for ordered lists, for example:

#. Parent ordered item.

   * Child unordeded item.

     #. Child ordered item.
     #. Child ordered item.

Renders as:

  1. Parent numbered item.

    • Child unordered item.

      1. Child ordered item.

      2. Child ordered item.

Code

Prefer code-blocks to code directives, because code-blocks have more options, such as showing line numbers and emphasizing lines.

For example,

.. code-block:: python
   :linenos:
   :emphasize-lines: 2

   def hello_world():
       string = "Hello world"
       print(string)

Renders as

1def hello_world():
2    string = "Hello world"
3    print(string)

Images

Prefer the SVG format for images, and save it as Optimized SVG in inkscape to use less space.

Store them in a hierarchically, do not use images subdirectories. The idea is to have simpler relative paths, for example, e.g.:

.. image:: ad2234_sdz_schematic.svg

Instead of over complicated paths like:

.. image:: ../../project/images/ad2234_sdz/ad2234_sdz_schematic.svg

In general, this avoids dangling artifacts and keeps the documentation simple.

Git Large File Storage

Where applicable, Git Large File Storage (LFS) is used to replace large files with text pointers inside Git, reducing cloning time.

To setup, install from your package manager and init:

apt install git-lfs
git lfs install

The files that will use Git LFS are tracked at .gitattributes, to add new files use a pattern at the repo root, for example:

git lfs track *.jpg

Or edit .gitattributes directly.

Vivado block-diagrams

Vivado block-diagrams can be exported as PDF and then converted to SVG with Inkscape.

Vivado waveform data

There is no way to export Vivado waveform data as vectors. Therefore, the recommended method is to take a PNG screenshot and use GIMP to export as 8bpc RGB with all metadata options disabled.

Note

Always use the Export As.. Ctrl+Shift+E option.

To reduce even further the size, you can use Color > Dither.. to reduce the number of colors in the PNG. Saving as greyscale also reduces the PNG size, but might reduce readability and it is not recommended.

Third-party directives and roles

Third-party tools are used to expand Sphinx functionality, if you haven’t already, do:

pip install -r requirements.txt

Custom directives and roles

To expand Sphinx functionality beyond existing tools, custom directives and roles have been written, which are located in the docs/extensions folder. Extensions are straight forward to create, if some functionality is missing, consider requesting or creating one.

Note

Link-like roles use the :role:`text <link>` synthax, like external links, but without the undescore in the end.

Color role

To print text in red or green, use :red:`text` and :green:`text`.

HDL build status directive

The HDL build status directive gets information from a markdown formatted status table (output.md) and generates a table with the build statuses.

The directive syntax is:

.. hdl-build-status::
   :file: <build_status_file>

The :path: option is optional, in the sense that if it’s not provided, no table is generated. If provided, but the build status file does not exist, an error is thrown.

Note

The :path: option is meant to be “filled” during a CI procedure.

HDL parameters directive

The HDL parameters directive gets information parsed from IP-XACT (component.xml) library and generates a table with the IP parameters.

Note

The IP-XACT files are generated by Vivado during the library build and not by the documentation tooling.

The directive syntax is:

.. hdl-parameters::
   :path: <ip_path>

   * - <parameter>
     - <description>

For example:

.. hdl-parameters::
   :path: library/spi_engine/spi_engine_interconnect

   * - DATA_WIDTH
     - Data width of the parallel SDI/SDO data interfaces.
   * - NUM_OF_SDI
     - Number of SDI lines on the physical SPI interface.

Descriptions in the directive have higher precedence than in the component.xml file.

The :path: option is optional, and should not be included if the documentation file path matches the component.xml hierarchically.

HDL interface directive

The HDL interfaces directive gets information parsed from component.xml library and generates tables with the IP interfaces, both buses and ports.

Note

The component.xml files are generated by Vivado during the library build and not by the documentation tooling.

The directive syntax is:

.. hdl-interfaces::
   :path: <ip_path>

   * - <port/bus>
     - <description>

For example:

.. hdl-interfaces::
   :path: library/spi_engine/spi_engine_interconnect

Descriptions in the directive have higher precedence than in the component.xml file. You can provide description to a port or a bus, but not for a bus port. Ports/buses that are consecutive are squashed into a single instance to avoid repetition, for example:

{data_tx_12_p, data_tx_23_p} -> data_tx_*_p
{data_tx_12, data_tx_23} -> data_tx_*
{adc_data_i0, adc_data_i0} -> adc_data_i*
{adc_data_q0, adc_data_q0} -> adc_data_q*
{rx_phy2, rx_phy4} -> rx_phy*

To provide a description to the squashed signals/buses, write, for example, data_tx_* once instead of the original name of all.

Warning

Do not create new IP with signals named as _phy*, it was added for legacy puporses, instead suffix with _*, e.g. mysignal_phy_4.

The :path: option is optional, and should not be included if the documentation file path matches the component.xml hierarchically.

HDL component diagram directive

The HDL component diagram directive gets information parsed from component.xml library and generates a component diagram for the IP with buses and ports information.

Note

The component.xml files are generated by Vivado during the library build and not by the documentation tooling.

The directive syntax is:

.. hdl-component-diagram::
   :path: <ip_path>

For example:

.. hdl-component-diagram::
   :path: library/spi_engine/spi_engine_interconnect

The :path: option is optional, and should not be included if the documentation file path matches the component.xml hierarchically.

Note

This directive replaces the deprecated symbolator directive.

HDL regmap directive

The HDL regmap directive gets information from docs/regmap/adi_regmap_*.txt files and generates tables with the register maps.

The directive syntax is:

.. hdl-regmap::
   :name: <regmap_name>
   :no-type-info:

For example:

.. hdl-regmap::
   :name: DMAC

Note

The register map name is the title-tool, the value above ENDTITLE in the source file.

This directive does not support content for descriptions, since the source file already have proper descriptions.

The :name: option is required, because the title tool does not match the IP name and one single docs/regmap/adi_regmap_*.txt file can have more than one register map. The :no-type-info: option is optional, and should not be included if it is in the main IP documentation page. It appends an auxiliary table explaining the register access types.

Collapsible directive

The collapsible directive creates a collapsible/dropdown/”HTML details”.

The directive syntax is:

.. collapsible:: <label>

   <content>

For example:

.. collapsible:: Python code example.

   .. code:: python

      print("Hello World!")

Renders as:

print("Hello World!")

Notice how you can use any Sphinx syntax, even nest other directives.

Video directive

The video directive creates a embedded video. Currently, direct MP4 and youtube embed links are supported, but could be easily expanded to support third-party services.

The directive syntax is:

.. video:: <url>

For example:

.. video:: http://ftp.fau.de/fosdem/2015/devroom-software_defined_radio/iiosdr.mp4

Renders as:

And:

.. video:: https://www.youtube.com/watch?v=p_VntEwUe24

Renders as:

ESD warning directive

The ESD warning directive creates a ESD warning, for example:

.. esd-warning::

Renders as:

All the products described on this page include ESD (electrostatic discharge) sensitive devices. Electrostatic charges as high as 4000V readily accumulate on the human body or test equipment and can discharge without detection. Although the boards feature ESD protection circuitry, permanent damage may occur on devices subjected to high-energy electrostatic discharges. Therefore, proper ESD precautions are recommended to avoid performance degradation or loss of functionality. This includes removing static charge on external equipment, cables, or antennas before connecting to the device.

Global options for directives

Set hide_collapsible_content to True to hide the collapsibles by default.

Set monolithic to True prefix paths with repos/<repo>. This is meant for the System Top Documentation repository only.

Common sections

HDL common sections

The More information and Support sections that are present in the HDL project documentation, are actually separate pages inserted as links. They’re located at hdl/projects/common/more_information.rst and /support.rst, and cannot be referenced here because they don’t have an ID at the beginning of the page, so not to have warnings when the documentation is rendered that they’re not included in any toctree.

They are inserted like this:

.. include:: ../common/more_information.rst

.. include:: ../common/support.rst

And will be rendered as sections of the page.

Dynamic elements

Dynamic elements refer to sections of the generated webpage that updates when loaded online from a source of truth, in general, doctools/*.json files; it uses a concept similar to “react components”.

These *.json files are generated when doctools_export_metadata is true in the conf.py. From the JavaScript side, it fetches from {content_root}[../versioned]/../doctools/[versioned]/metadata.json.

Note

path version is present and set if latest exists at {content_root}/../doctools and the stored version can be extracted.

The dynamic elements are:

  • The navigation bar at the top is updated using the repotoc entry in doctools/metadata.json.

  • A banner at the top is present/updated when the banner entry in doctools/metadata.json exists.