diff --git a/doc/lxsocdoc.md b/doc/lxsocdoc.md new file mode 100644 index 000000000..b61e5b834 --- /dev/null +++ b/doc/lxsocdoc.md @@ -0,0 +1,147 @@ +# lxsocdoc: Document your LiteX SoC Automatically + +`lxsocdoc` lets you take a synthesized LiteX SoC and generate full +register-level documentation. Additionally, it will generate `.svd` files, +suitable for use with various header generation programs. + +## Required Software + +You must have `sphinx` and `sphinx.wavedrom` installed in order to build +the documentation. These can be installed with pip: + +``` +$ pip3 install sphinxcontrib-wavedrom sphinx +``` + +## Usage + +To use `lxsocdoc`, import the module and call `lxsocdoc.generate_docs(soc, path)`. +You can also generate an SVD file. For example: + +```python +import lxsocdoc + +... + soc = BaseSoC(platform) + builder = Builder(soc) + vns = builder.build() + soc.do_exit(vns) + lxsocdoc.generate_docs(soc, "build/documentation") + lxsocdoc.generate_svd(soc, "build/software") +``` + +After you build your design, you will have a Sphinx documentation source available +in the above directory. To build this into a target document, use `sphinx-build`. + +For example, if `sphinx-build` is in your path, you can run: + +`sphinx-build -M html build/documentation/ build/documentation/_build` + +`sphinx-build` may be located in `~/.local/bin/` depending on your installation environment. + +You can then verify the contents by starting a local webserver and opening a web +browser to [localhost:8000](http://localhost:8000): + +`python3 -m http.server --directory build/documentation/_build/html` + +## Documenting your Registers + +You can add documentation to your registers by defining your `CSRStorage` and `CSRStatus` registers with an additional `field` list. For example: + +```python +self.bitbang = CSRStorage(4, fields=[ + CSRField("mosi", description="Output value for MOSI..." + CSRField("clk", description="Output value for SPI CLK..." + CSRField("cs_n", description="Output value for SPI C..." + CSRField("dir", description="Sets the dir...", values=[ + ("0", "OUT", "SPI pins are all output"), + ("1", "IN", "SPI pins are all input"), + ]) +], description="""Bitbang controls for SPI output. Only + standard 1x SPI is supported, and as a result all + four wires are ganged together. This means that it + is only possible to perform half-duplex operations, + using this SPI core.""") +``` + +There are several interesting properties here: + +* The first argument to a `CSRStorage` or `CSRStatus` is the bit width. +* You can pass a list of `CSRField` objects, which will get turned into bit fields +* Both `CSRStorage` and `CSRStatus` support a freeform `description` property that will be used to describe the overall register. + +A `CSRField` object has the following properties: + +* `name`: The short name of the register. This should be just a few characters long, as it will be used in the register diagram as well as accessor objects. **Required** +* `size`: The size of this field. This is optional, and defaults to `1` +* `offset`: The offset of this particular field. If unspecified, defaults to following the previous field. Use this to add gaps to your register definitions, for example to have reserved fields. +* `reset`: If specified, the value of this field at reset. Defaults to `0`. +* `description`: A textual description of this register. This is optional, but should be specified because it provides critical information to the user about what this field does. +* `pulse`: If `True`, then this value is `1` only for one clock cycle after the user writes a `1` to this field. This is especially useful for `START` bits used to initiate operations, or `RESET` bits used to clear an operation. +* `access`: The accessibility of this field. One of `CSRAccess.ReadWrite`, `CSRAccess.WriteOnly`, or `CSRAccess.ReadOnly` +* `values`: If present, a list of tuples of values. The first field is the numeric value, with `x` for `don't care`. The second field, if present, is the short name of the value. The final field is a textual description of the value. For example: + +```python + [ + ("0b0000", "disable the timer"), + ("0b0001", "slow", "slow timer"), + ("0b1xxx", "fast timer"), + ] +``` + +## Further Module Documentation + +You can add additional documentation to your module with the `ModuleDoc` class. Add it to your base object. + +**To use further Module Documentation, your Module must inherit from `AutoDoc`**. For example: + +```python +from litex.soc.integration.doc import AutoDoc, ModuleDoc +class DocExample(Module, AutoCSR, AutoDoc): + def __init__(self): + self.mydoc = ModuleDoc("Some documentation") +``` + +You may pass a single string to the constructor, in which case the first line becomes the title, or you may pass a separate `title` and `body` parameters to the constructor. For example: + +```python + self.intro = ModuleDoc("""Introduce ModuleDoc + + This is an example of how to document using ModuleDoc. An additional + section will get added to the output documentation for this module, + with the title ``Introduce ModuleDoc`` and with this paragraph + as a body""") +``` + +Note that the default documentatino format is `rst`. You can switch to markdown by passing `format="markdown"` to the constructor, however support is not very good. + +### External Documentation + +You can have external documentation by passing `file` to the constructor. +For example: + +```python + self.extra_doc = ModuleDoc(file="extra_doc.rst") +``` + +This will be included at build-time. + +### Using Python Docstrings + +You can also simply have your module inherit from `ModuleDoc`, in which case +the documentation will be taken from the docstring. For example: + +```python +from litex.soc.integration.doc import AutoDoc, ModuleDoc +class DocExample(Module, AutoCSR, AutoDoc, ModuleDoc): + """ + Automatically Documented Module + + This module will be automatically documented, and included in the + generated module documentation output. You can add additional + ModuleDoc objects to this module, in order to add further subsections + to the output docs. + """ + def __init__(self): + pass +```