lca2020-pay-it-forward/index.html

286 lines
11 KiB
HTML
Raw Normal View History

2012-10-21 01:14:50 +00:00
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Paying It Forward: Documenting your Hardware</title>
<meta name="description" content="A framework for easily creating beautiful presentations using HTML">
<meta name="author" content="Sean &quot;xobs&quot; Cross">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<link rel="stylesheet" href="css/reveal.css">
<link rel="stylesheet" href="css/theme/lca2019.css" id="theme">
<!-- Theme used for syntax highlighting of code -->
<link rel="stylesheet" href="lib/css/zenburn.css">
<!-- Printing and PDF exports -->
<script>
var link = document.createElement('link');
link.rel = 'stylesheet';
link.type = 'text/css';
link.href = window.location.search.match(/print-pdf/gi) ? 'css/print/pdf.css' : 'css/print/paper.css';
document.getElementsByTagName('head')[0].appendChild(link);
</script>
<!--[if lt IE 9]>
<script src="lib/js/html5shiv.js"></script>
<![endif]-->
<style>
/*********************************************
* ZOOM REVERSE TRANSITION (i.e. zoom out)
*********************************************/
.reveal .slides section[data-transition=zoomrev],
.reveal.zoomrev .slides section:not([data-transition]) {
transition-timing-function: ease;
}
.reveal .slides > section[data-transition=zoomrev].past,
.reveal .slides > section[data-transition~=zoomrev-out].past,
.reveal.zoomrev .slides > section:not([data-transition]).past {
visibility: hidden;
-webkit-transform: scale(0.2);
transform: scale(0.2);
}
.reveal .slides > section[data-transition=zoomrev].future,
.reveal .slides > section[data-transition~=zoomrev-in].future,
.reveal.zoomrev .slides > section:not([data-transition]).future {
visibility: hidden;
-webkit-transform: scale(16);
transform: scale(16);
}
.reveal .slides > section > section[data-transition=zoomrev].past,
.reveal .slides > section > section[data-transition~=zoomrev-out].past,
.reveal.zoomrev .slides > section > section:not([data-transition]).past {
-webkit-transform: translate(0, 150%);
transform: translate(0, 150%);
}
.reveal .slides > section > section[data-transition=zoomrev].future,
.reveal .slides > section > section[data-transition~=zoomrev-in].future,
.reveal.zoomrev .slides > section > section:not([data-transition]).future {
-webkit-transform: translate(0, -150%);
transform: translate(0, -150%);
}
</style>
</head>
<body>
<!-- Start of main presentation -->
<div class="reveal">
<div class="footer">
<a class="url" href="https://p.xobs.io/lca20-pif/">p.xobs.io/lca20-pif</a>
<span class="theme">The Linux of Things</span><span class="hashtag"> | #LCA2020</span><span class="twitter"> |
@linuxconfau</span>
2011-06-07 19:10:59 +00:00
</div>
<div class="slides">
<section data-background-image="css/theme/lca2019-title-bg-transparent.svg">
<h1>Paying it Forward: Documenting Your Hardware Project</h1>
<h4>Approaches to documenting a hardware description language using lxsocdoc</h4>
<p align="right">
<small>Sean Cross - <a href="https://xobs.io/">https://xobs.io/</a> - @xobs</small>
</p>
</section>
<section>
<h1>Hardware is different</h1>
<ol>
<li>Massively Parallel</li>
</ol>
</section>
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
the hardware in addition to making modifications to your software package.
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 Fomu project, and this talk will cover some of the issues I've run into with
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
Language you may use.
Common approaches today involve comments in the HDL and/or C header files. This
works, but we can do better. We just need to describe the hardware better.
```//Hardware definitions of the SoC. Also is the main repo of documentation for the
//programmer-centric view of the hardware.```
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
a design file -- either Verilog code, or a Yosys netlist. There are many other
alternatives such as SpinalHDL or Chisel. By writing in Python as opposed to
direct Verilog, we get a lot of nice primitives.
CSRStorage and CSRStatus are two such primitives. These enable trivial access to
a hardware device from a CPU softcore. Instead of manually wiring up a crossbar
and decoding the addresses ourselves, we just need to write `self.regname = CSRStatus(8)`,
and the build system will wire up 8 bits of read-only memory to the target CPU.
Similarly, `self.othername = CSRStorage(8)` will give 8-bits of write-only memory.
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
driver worked. There wasn't any documentation except the source, which looked
like this:
self.bitbang = CSRStorage(4)
If(self.bitbang.storage[3],
dq.oe.eq(0)
).Else(
dq.oe.eq(1)
),
If(self.bitbang.storage[1], # CPOL=0/CPHA=0 or CPOL=1/CPHA=1 only.
self.miso.status.eq(dq.i[1])
),
dq.o.eq(Cat(self.bitbang.storage[0], Replicate(1, spi_width-1)))
You can kind of understand it, but it does take a lot of mental power to
work through it. I started by creating aliases for the various elements
in the storage array, but then I thought: There has to be a better way!
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
more information to the CSR objects to make our life easier. So after
working with the LiteX creator Florent, we refactored the bitbang
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.
""")
Now the actual bitbang logic looks like:
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
in an array to determine what field does what. Instead we get actual named fields.
But because Python can introspect Python very easily, this is just the beginning.
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
information. We can actually generate a full reference manual, just like one you
would receive from a SoC Vendor.
For example, this is what the start of the Fomu SPI Flash documentation looks like:
[Register Listing for LXSPI]
This is already pretty useful. You can hand this file to someone and show them
how your design works. But the title of this talk is called "Paying it Forward",
and I can tell you from experience that having such a reference manual for yourself
while developing software for your own hardware is still invaluable. Hardware
designs are complex things, and not having to decode bitfield offsets in your
head or constantly referring to various sections of code to see how it's implemented
saves valuable time.
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
background information on protocols, as well as more elaboration on how the block
works.
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> <!-- class="reveal" -->
<!-- End of main presentation -->
<!-- Start of configuration section -->
<script src="lib/js/head.min.js"></script>
<script src="js/reveal.js"></script>
<script>
var presenter = !!Reveal.getQueryHash().s;
// More info https://github.com/hakimel/reveal.js#configuration
Reveal.initialize({
controls: presenter ? false : true,
progress: true,
history: true,
center: true,
controlsTutorial: presenter ? false : true,
slideNumber: presenter ? null : 'c/t',
// The "normal" size of the presentation, aspect ratio will be preserved
// when the presentation is scaled to fit different resolutions. Can be
// specified using percentage units.
width: 960,
height: 700,
// Factor of the display size that should remain empty around the content
margin: 0.1,
multiplex: {
url: 'https://p.xobs.io/',
id: '631bb3db6fbaea78',
secret: Reveal.getQueryHash().s || null
},
// Bounds for smallest/largest possible scale to apply to content
minScale: 0.02,
maxScale: 5.5,
transition: 'slide', // none/fade/slide/convex/concave/zoom
// More info https://github.com/hakimel/reveal.js#dependencies
dependencies: [
{ src: 'lib/js/classList.js', condition: function () { return !document.body.classList; } },
{ src: 'plugin/markdown/marked.js', condition: function () { return !!document.querySelector('[data-markdown]'); } },
{ src: 'plugin/markdown/markdown.js', condition: function () { return !!document.querySelector('[data-markdown]'); } },
{ src: 'plugin/highlight/highlight.js', async: true, callback: function () { hljs.initHighlightingOnLoad(); } },
{ src: 'plugin/search/search.js', async: true },
{ src: 'plugin/zoom-js/zoom.js', async: true },
{ src: 'plugin/notes/notes.js', async: true },
{ src: 'lib/js/socket.io.js', async: true },
{
src: presenter ?
'plugin/multiplex/master.js' :
'plugin/multiplex/client.js', async: true
},
]
});
</script>
</body>
2012-03-24 16:48:16 +00:00
</html>