index: add section headers
Signed-off-by: Sean Cross <sean@xobs.io>
This commit is contained in:
parent
0737480489
commit
073c9f7370
119
index.html
119
index.html
@ -94,6 +94,7 @@
|
|||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
|
<h2>Introduction</h2>
|
||||||
<aside class="notes">
|
<aside class="notes">
|
||||||
This is the Open ISA miniconf, which today tends to mean FPGAs. This means that
|
This is the Open ISA miniconf, which today tends to mean FPGAs. This means that
|
||||||
hardware and software are both extensible, and developers will be able to extend
|
hardware and software are both extensible, and developers will be able to extend
|
||||||
@ -102,6 +103,21 @@
|
|||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
|
<h2>About Me</h2>
|
||||||
|
<aside class="notes">
|
||||||
|
My name is Sean Cross, also known as "xobs". I will be speaking later this week
|
||||||
|
on the Betrusted project, but many know me as the main developer behind the Fomu
|
||||||
|
project. Fomu is an FPGA that fits in your USB port. One of my goals with the
|
||||||
|
Fomu project was to allow people to treat it as just a RISC-V CPU in their USB
|
||||||
|
port, which means now we need to make documentation. This talk covers some of
|
||||||
|
the problems I ran into while working on this project, and the solutions I came
|
||||||
|
up with.
|
||||||
|
</aside>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h2>Undocumented Hardware = Bad</h2>
|
||||||
|
<h4>(But so easy to do!)</h4>
|
||||||
<aside class="notes">
|
<aside class="notes">
|
||||||
Undocumented hardware is bad. There are all sorts of quirks, and even if you have
|
Undocumented hardware is bad. There are all sorts of quirks, and even if you have
|
||||||
the source code, it can be very difficult to read. I'm the primary developer for
|
the source code, it can be very difficult to read. I'm the primary developer for
|
||||||
@ -109,10 +125,15 @@
|
|||||||
respect to documentation. It is most directly related to the LiteX and Migen
|
respect to documentation. It is most directly related to the LiteX and Migen
|
||||||
projects, but the concepts will carry over into any other Hardware Description
|
projects, but the concepts will carry over into any other Hardware Description
|
||||||
Language you may use.
|
Language you may use.
|
||||||
|
|
||||||
|
The goal of this talk is to show how it's easy to document hardware with
|
||||||
|
the right framework, and how it's easier to have a project that's documented
|
||||||
|
than one that isn't.
|
||||||
</aside>
|
</aside>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
|
<h2>Talk Outline</h2>
|
||||||
<aside class="notes">
|
<aside class="notes">
|
||||||
I'll briefly cover various methods of writing HDL code, then cover the rationale
|
I'll briefly cover various methods of writing HDL code, then cover the rationale
|
||||||
behind the approach we take with lxsocdoc, then give an example of how to use
|
behind the approach we take with lxsocdoc, then give an example of how to use
|
||||||
@ -122,6 +143,7 @@
|
|||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
|
<h2>Motivation</h2>
|
||||||
<aside class="notes">
|
<aside class="notes">
|
||||||
Verilog and VHDL are kind of the C or assembly of the FPGA world. They're universal,
|
Verilog and VHDL are kind of the C or assembly of the FPGA world. They're universal,
|
||||||
but somewhat unwieldy to use. You need to manually set up your address decoders,
|
but somewhat unwieldy to use. You need to manually set up your address decoders,
|
||||||
@ -134,6 +156,7 @@
|
|||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
|
<h2>About LiteX and lxsocdoc</h2>
|
||||||
<aside class="notes">
|
<aside class="notes">
|
||||||
Fomu uses LiteX, which is related to Migen. This is a hardware description language
|
Fomu uses LiteX, which is related to Migen. This is a hardware description language
|
||||||
written in Python. You write Python code and run the program, and it generates
|
written in Python. You write Python code and run the program, and it generates
|
||||||
@ -146,6 +169,7 @@
|
|||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
|
<h2>LiteX Primitives</h2>
|
||||||
<aside class="notes">
|
<aside class="notes">
|
||||||
In LiteX, two of the primitives used to expose hardware registers to the CPU softcore
|
In LiteX, two of the primitives used to expose hardware registers to the CPU softcore
|
||||||
are CSRStorage and CSRStatus. Instead of manually wiring up a crossbar and decoding
|
are CSRStorage and CSRStatus. Instead of manually wiring up a crossbar and decoding
|
||||||
@ -163,10 +187,13 @@ If(self.bitbang.storage[3],
|
|||||||
).Else(
|
).Else(
|
||||||
dq.oe.eq(1)
|
dq.oe.eq(1)
|
||||||
),
|
),
|
||||||
If(self.bitbang.storage[1], # CPOL=0/CPHA=0 or CPOL=1/CPHA=1 only.
|
# CPOL=0/CPHA=0 or CPOL=1/CPHA=1 only.
|
||||||
|
If(self.bitbang.storage[1],
|
||||||
self.miso.status.eq(dq.i[1])
|
self.miso.status.eq(dq.i[1])
|
||||||
),
|
),
|
||||||
dq.o.eq(Cat(self.bitbang.storage[0], Replicate(1, spi_width-1)))</code></pre>
|
dq.o.eq(
|
||||||
|
Cat(self.bitbang.storage[0], Replicate(1, spi_width-1))
|
||||||
|
)</code></pre>
|
||||||
<aside class="notes">
|
<aside class="notes">
|
||||||
This works well, but exposes a new problem: Documentation. As an example, I was
|
This works well, but exposes a new problem: Documentation. As an example, I was
|
||||||
working with the SPI Flash block in litex, and wanted to know how the bitbang
|
working with the SPI Flash block in litex, and wanted to know how the bitbang
|
||||||
@ -180,6 +207,7 @@ dq.o.eq(Cat(self.bitbang.storage[0], Replicate(1, spi_width-1)))</code></pre>
|
|||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
|
<h2>Aside: Python Docstrings</h2>
|
||||||
<aside class="notes">
|
<aside class="notes">
|
||||||
As an aside, Python has something called Pydoc and Docstrings. These are
|
As an aside, Python has something called Pydoc and Docstrings. These are
|
||||||
comments that go at the top of functions and classes that let you describe
|
comments that go at the top of functions and classes that let you describe
|
||||||
@ -191,42 +219,45 @@ dq.o.eq(Cat(self.bitbang.storage[0], Replicate(1, spi_width-1)))</code></pre>
|
|||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
|
<h4>New Register Definition</h4>
|
||||||
|
<pre><code class="python" data-trim>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.
|
||||||
|
""")</code></pre>
|
||||||
<aside class="notes">
|
<aside class="notes">
|
||||||
This is when I hit upon the idea of `lxsocdoc`. The basic idea is that
|
This is when I hit upon the idea of `lxsocdoc`. The basic idea is that
|
||||||
Python is really good at introspecting Python, so let's add a little bit
|
Python is really good at introspecting Python, so let's add a little bit
|
||||||
more information to the CSR objects to make our life easier. And so, after
|
more information to the CSR objects to make our life easier. And so, after
|
||||||
working with the LiteX creator Florent, we refactored the bitbang
|
working with the LiteX creator Florent, we refactored the bitbang
|
||||||
definition to this:
|
definition to this.
|
||||||
|
|
||||||
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.
|
|
||||||
""")
|
|
||||||
</aside>
|
</aside>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
|
<h4>Refactored SPI Bitbang</h4>
|
||||||
|
<pre><code class="python" data-trim>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))
|
||||||
|
)</code></pre>
|
||||||
<aside class="notes">
|
<aside class="notes">
|
||||||
Now the actual bitbang logic looks like:
|
Now the actual bitbang logic looks like this.
|
||||||
|
|
||||||
If(self.bitbang.fields.dir,
|
|
||||||
dq.oe.eq(0)
|
|
||||||
).Else(
|
|
||||||
dq.oe.eq(1)
|
|
||||||
),
|
|
||||||
If(self.bitbang.fields.clk, # CPOL=0/CPHA=0 or CPOL=1/CPHA=1 only.
|
|
||||||
self.miso.status.eq(dq.i[1])
|
|
||||||
),
|
|
||||||
dq.o.eq(Cat(self.bitbang.fields.mosi, Replicate(1, spi_width-1)))
|
|
||||||
|
|
||||||
This is a little bit easier to understand -- no longer are we looking at indices
|
This is a little bit easier to understand -- no longer are we looking at indices
|
||||||
in an array to determine what field does what. Instead we get actual named fields.
|
in an array to determine what field does what. Instead we get actual named fields.
|
||||||
@ -235,6 +266,7 @@ dq.o.eq(Cat(self.bitbang.storage[0], Replicate(1, spi_width-1)))</code></pre>
|
|||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
|
<h2>Generating a Manual</h2>
|
||||||
<aside class="notes">
|
<aside class="notes">
|
||||||
After the design is elaborated and the output file is generated, we can iterate
|
After the design is elaborated and the output file is generated, we can iterate
|
||||||
through the resulting tree and pick out any CSR objects and using any additional
|
through the resulting tree and pick out any CSR objects and using any additional
|
||||||
@ -255,6 +287,7 @@ dq.o.eq(Cat(self.bitbang.storage[0], Replicate(1, spi_width-1)))</code></pre>
|
|||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
|
<h2>More Documentation: ModuleDoc</h2>
|
||||||
<aside class="notes">
|
<aside class="notes">
|
||||||
So now we have register documentation. Can we do better? Of course we can.
|
So now we have register documentation. Can we do better? Of course we can.
|
||||||
SoC reference manuals are more than just register definitions. They also include
|
SoC reference manuals are more than just register definitions. They also include
|
||||||
@ -263,9 +296,19 @@ dq.o.eq(Cat(self.bitbang.storage[0], Replicate(1, spi_width-1)))</code></pre>
|
|||||||
in a similar fashion.
|
in a similar fashion.
|
||||||
</aside>
|
</aside>
|
||||||
</section>
|
</section>
|
||||||
---ModuleDoc---
|
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
|
<h2>Protocol Documentation</h2>
|
||||||
|
<aside class="notes">
|
||||||
|
We can add additional documentation such as protocol waveforms. Here
|
||||||
|
we use WaveDrom to define the protocol of Wishbone-over-SPI. There
|
||||||
|
are multiple formats of the protocol depending on which version is
|
||||||
|
instantiated.
|
||||||
|
</aside>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h2>SVD: Documentation for Machines</h2>
|
||||||
<aside class="notes">
|
<aside class="notes">
|
||||||
Having documentation for humans is great, but we can go one step further and
|
Having documentation for humans is great, but we can go one step further and
|
||||||
make documentation for computers. SVD is an XML format defined by ARM that
|
make documentation for computers. SVD is an XML format defined by ARM that
|
||||||
@ -276,6 +319,7 @@ dq.o.eq(Cat(self.bitbang.storage[0], Replicate(1, spi_width-1)))</code></pre>
|
|||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
|
<h2>SVD2Rust: Generating Safe Accessors</h2>
|
||||||
<aside class="notes">
|
<aside class="notes">
|
||||||
In addition to generating a reference manual for humans, we can generate an SVD
|
In addition to generating a reference manual for humans, we can generate an SVD
|
||||||
file that's usable in a wide variety of areas. For example, we can turn an SVD
|
file that's usable in a wide variety of areas. For example, we can turn an SVD
|
||||||
@ -285,28 +329,13 @@ dq.o.eq(Cat(self.bitbang.storage[0], Replicate(1, spi_width-1)))</code></pre>
|
|||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
|
<h2>Renode: Fancy Register Logging</h2>
|
||||||
<aside class="notes">
|
<aside class="notes">
|
||||||
We can also import this SVD file into an emulator such as Renode, which will
|
We can also import this SVD file into an emulator such as Renode, which will
|
||||||
print out fields and flags that get accessed, giving us greater visibility into
|
print out fields and flags that get accessed, giving us greater visibility into
|
||||||
what a program is doing.
|
what a program is doing.
|
||||||
</aside>
|
</aside>
|
||||||
</section>
|
</section>
|
||||||
lxsocdoc
|
|
||||||
intro to litex/migen
|
|
||||||
concept of mixins
|
|
||||||
concept of documentation sections
|
|
||||||
what the output can look like
|
|
||||||
what's coming in the future
|
|
||||||
documenting interrupts
|
|
||||||
introspecting classes
|
|
||||||
other approaches
|
|
||||||
how you can help
|
|
||||||
why this helps you
|
|
||||||
|
|
||||||
Benefits:
|
|
||||||
* Generating reference manuals
|
|
||||||
* SVD
|
|
||||||
* SVD2Rust
|
|
||||||
</div>
|
</div>
|
||||||
</div> <!-- class="reveal" -->
|
</div> <!-- class="reveal" -->
|
||||||
<!-- End of main presentation -->
|
<!-- End of main presentation -->
|
||||||
|
Loading…
Reference in New Issue
Block a user