Paying it Forward: Documenting Your Hardware Project

Approaches to documenting a hardware description language using lxsocdoc

Sean Cross - https://xobs.io/ - @xobs

Introduction

About Me

Undocumented Hardware = Bad

(But so easy to do!)

Talk Outline

Motivation

About LiteX and lxsocdoc

LiteX Primitives

SPI Bitbang Module

self.bitbang = CSRStorage(4)
If(self.bitbang.storage[3],
	dq.oe.eq(0)
).Else(
	dq.oe.eq(1)
),
# CPOL=0/CPHA=0 or CPOL=1/CPHA=1 only.
If(self.bitbang.storage[1],
	self.miso.status.eq(dq.i[1])
),
dq.o.eq(
	Cat(self.bitbang.storage[0], Replicate(1, spi_width-1))
)

Aside: Python Docstrings

New Register Definition

self.bitbang = CSRStorage(4, fields=[
	CSRField("mosi", description="Output value for MOSI pin, valid whenever ``dir`` is ``0``."),
	CSRField("clk", description="Output value for SPI CLK pin."),
	CSRField("cs_n", description="Output value for SPI CSn pin."),
	CSRField("dir", description="Sets the direction for *ALL* SPI data pins except CLK and CSn.", 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.
""")

Refactored SPI Bitbang

If(self.bitbang.fields.dir,
	dq.oe.eq(0)
).Else(
	dq.oe.eq(1)
),
# CPOL=0/CPHA=0 or CPOL=1/CPHA=1 only.
If(self.bitbang.fields.clk,
	self.miso.status.eq(dq.i[1])
),
dq.o.eq(
	Cat(self.bitbang.fields.mosi, Replicate(1, spi_width-1))
)

Generating a Manual

More Documentation: ModuleDoc

Protocol Documentation

SVD: Documentation for Machines

SVD2Rust: Generating Safe Accessors

Renode: Fancy Register Logging