2012-10-21 01:14:50 +00:00
|
|
|
|
<!doctype html>
|
2016-03-20 17:50:14 +00:00
|
|
|
|
<html>
|
2020-01-02 03:01:08 +00:00
|
|
|
|
|
|
|
|
|
<head>
|
2020-01-02 08:45:42 +00:00
|
|
|
|
<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 "xobs" 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/lca2020.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>
|
2020-01-02 03:01:08 +00:00
|
|
|
|
|
|
|
|
|
</head>
|
|
|
|
|
|
|
|
|
|
<body>
|
|
|
|
|
|
2020-01-02 08:45:42 +00:00
|
|
|
|
<!-- 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>
|
2020-01-02 12:58:02 +00:00
|
|
|
|
<span class="theme">Who’s Watching</span><span class="hashtag"> | #LCA2020</span><span class="twitter"> |
|
2020-01-02 08:45:42 +00:00
|
|
|
|
@linuxconfau</span>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="slides">
|
|
|
|
|
<section data-background-image="css/theme/lca2019-title-bg-transparent.svg">
|
2020-01-02 13:00:39 +00:00
|
|
|
|
<h2 style="background-color: transparent;">Paying it Forward: Documenting Your Hardware Project</h2>
|
|
|
|
|
<h5 style="background-color: transparent;">Approaches to documenting a hardware description language using lxsocdoc</h5>
|
2020-01-02 08:45:42 +00:00
|
|
|
|
<p align="right">
|
|
|
|
|
<small>Sean Cross - <a href="https://xobs.io/">https://xobs.io/</a> - @xobs</small>
|
|
|
|
|
</p>
|
|
|
|
|
</section>
|
|
|
|
|
|
|
|
|
|
<section>
|
2020-01-03 02:58:11 +00:00
|
|
|
|
<h2>Undocumented Hardware = Bad</h2>
|
|
|
|
|
<h4 class="fragment">(But so easy to do!)</h4>
|
2020-01-02 08:45:42 +00:00
|
|
|
|
<aside class="notes">
|
2020-01-03 02:58:11 +00:00
|
|
|
|
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.
|
|
|
|
|
|
|
|
|
|
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.
|
2020-01-02 08:45:42 +00:00
|
|
|
|
</aside>
|
|
|
|
|
</section>
|
|
|
|
|
|
|
|
|
|
<section>
|
|
|
|
|
<h2>About Me</h2>
|
2020-01-03 02:00:18 +00:00
|
|
|
|
<table>
|
|
|
|
|
<tr>
|
|
|
|
|
<td><img data-src="img/me.jpg"></td>
|
|
|
|
|
<td><img data-src="img/fomu.png"></td>
|
|
|
|
|
</tr>
|
|
|
|
|
</table>
|
2020-01-02 08:45:42 +00:00
|
|
|
|
<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>
|
|
|
|
|
|
2020-01-11 10:18:44 +00:00
|
|
|
|
<section>
|
|
|
|
|
<h2>Reference Manuals</h2>
|
2020-01-12 23:43:41 +00:00
|
|
|
|
<img data-src="img/rm-registers.png">
|
2020-01-11 10:18:44 +00:00
|
|
|
|
<aside class="notes">
|
|
|
|
|
How many people here know what a reference manual is? These are documents that
|
|
|
|
|
you hopefully get from the manufacutrer of a chip that tell you how to use it.
|
|
|
|
|
These are the single most important part of developing a chip the normal way, as
|
|
|
|
|
they give you all of the information on how to use a chip. They can include
|
|
|
|
|
everything from which memory addresses to poke to cause a pin to become an output,
|
2020-01-12 23:43:41 +00:00
|
|
|
|
or how to set up the video block to output data. This is an example from the
|
|
|
|
|
i.MX6 reference manual, documenting the chip we used in Novena. This is from
|
|
|
|
|
midway through the I2C documentation. You can see they have some nice diagrams,
|
|
|
|
|
followed by a register map.
|
|
|
|
|
</aside>
|
|
|
|
|
</section>
|
|
|
|
|
|
|
|
|
|
<section>
|
|
|
|
|
<h2>Reference Manuals</h2>
|
|
|
|
|
<img data-src="img/rm-register-map.png">
|
|
|
|
|
<aside class="notes">
|
|
|
|
|
This is what a documented register looks like. When writing the drivers,
|
|
|
|
|
you usually spend most of your time studying these pages. These are invaluable
|
|
|
|
|
for getting to understand a brand-new chip. You can see here a register diagram
|
|
|
|
|
on the left, followed by a table of the register meanings, occasionally followed
|
|
|
|
|
by extra documentation on a particular register.
|
|
|
|
|
</aside>
|
|
|
|
|
</section>
|
|
|
|
|
|
|
|
|
|
<section>
|
|
|
|
|
<h2>Reference Manuals</h2>
|
|
|
|
|
<img data-src="img/rm-example.png">
|
|
|
|
|
<h6 class="fragment">Datasheet ≠ Reference Manual</h6>
|
|
|
|
|
<aside class="notes">
|
|
|
|
|
Here is the first page from that reference manual for the i.MX6 used in the Novena.
|
|
|
|
|
These tend to include lots of sections that are just explanatory, and this Introduction
|
|
|
|
|
describes the features of the chip along with background on why some of the choices
|
|
|
|
|
were made.
|
|
|
|
|
As an aside, reference manuals aren't datasheets -- datasheets tend to include
|
|
|
|
|
electrical and operating information, and tend to be much shorter. If you're
|
|
|
|
|
workong on software, you want a reference manual. If you're putting the chip on
|
|
|
|
|
a board, or you're trying to figure out specific values such as maximum frequency
|
|
|
|
|
or operating temperature, you want a datasheet.
|
2020-01-11 10:18:44 +00:00
|
|
|
|
</aside>
|
|
|
|
|
</section>
|
2020-01-12 06:16:44 +00:00
|
|
|
|
|
|
|
|
|
<section>
|
|
|
|
|
<h2>Lots of Documentation</h2>
|
|
|
|
|
<img data-src="img/rm-page-numbers.png">
|
|
|
|
|
<aside class="notes">
|
|
|
|
|
This documentation is very extensive. The start of Chapter 1 is on page 197, with all
|
2020-01-12 23:43:41 +00:00
|
|
|
|
previous pages being the Table of Contents. That's almost 6000 pages. It's very
|
|
|
|
|
extensive, because it's a very complicated chip. These documents are so important
|
|
|
|
|
that there are entire black markets dedicated to selling them. As open source people,
|
|
|
|
|
if we want a chip to be considered open, it needs to have open documentation.
|
2020-01-12 06:16:44 +00:00
|
|
|
|
</aside>
|
|
|
|
|
</section>
|
|
|
|
|
|
2020-01-02 08:45:42 +00:00
|
|
|
|
<section>
|
2020-01-03 02:58:11 +00:00
|
|
|
|
<h2>Enterprise Documentation</h2>
|
|
|
|
|
<table>
|
|
|
|
|
<tr>
|
|
|
|
|
<td>
|
|
|
|
|
<img height="400" class="fragment" data-src="img/Microsoft_Office_Word.svg" type="image/svg+xml"/>
|
|
|
|
|
</td>
|
|
|
|
|
<td width="50%">
|
|
|
|
|
<div class="fragment">
|
|
|
|
|
<img data-src="img/Git-logo.svg" type="image/svg+xml"/>
|
|
|
|
|
<img data-src="img/Travis_CI_Logo.svg" type="img/svg+xml"/>
|
|
|
|
|
</div>
|
|
|
|
|
</td>
|
|
|
|
|
</tr>
|
|
|
|
|
</table>
|
2020-01-02 08:45:42 +00:00
|
|
|
|
<aside class="notes">
|
2020-01-11 10:18:44 +00:00
|
|
|
|
So how is this monster of a document written? I've asked several documentation
|
|
|
|
|
writers from professional chip vendors, and they say that they have a whole team
|
|
|
|
|
of people using a very advanced piece of realtime typesetting software.
|
2020-01-03 02:58:11 +00:00
|
|
|
|
Most enterprise documentation is written by a team of writers using Microsoft Word.
|
|
|
|
|
We're open source developers, and we prefer to use our own tools such as Git and CI
|
|
|
|
|
to create documentation for us. Because we're lazy. And prone to making mistakes.
|
2020-01-02 08:45:42 +00:00
|
|
|
|
</aside>
|
|
|
|
|
</section>
|
|
|
|
|
|
|
|
|
|
<section>
|
|
|
|
|
<h2>Talk Outline</h2>
|
|
|
|
|
<ol>
|
2020-01-13 00:16:00 +00:00
|
|
|
|
<li>Motivation behind <tt>lxsocdoc</tt></li>
|
|
|
|
|
<li>Writing Python HDL Code</li>
|
2020-01-02 08:45:42 +00:00
|
|
|
|
<li>Examples of <tt>lxsocdoc</tt></li>
|
|
|
|
|
<li>Benefits of this approach</li>
|
|
|
|
|
</ol>
|
|
|
|
|
<aside class="notes">
|
|
|
|
|
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
|
|
|
|
|
lxsocdoc and how you might apply it to your language. Finally, I'll cover the
|
|
|
|
|
implications of having documented hardware and how this will help you pay it forward.
|
|
|
|
|
</aside>
|
|
|
|
|
</section>
|
|
|
|
|
|
|
|
|
|
<section>
|
|
|
|
|
<h2>Motivation</h2>
|
|
|
|
|
<pre><code class="hljs cpp">// Hardware definitions of the SoC. Also is the main repo of
|
2020-01-02 08:33:07 +00:00
|
|
|
|
// documentation for the programmer-centric view
|
|
|
|
|
// of the hardware.
|
|
|
|
|
/* Start of memory range for the UART peripheral */
|
|
|
|
|
#define UART_OFFSET 0x10000000
|
|
|
|
|
/* Offset of the data register for the debug UART. A write
|
|
|
|
|
here will send the data out of the UART. A write when a
|
|
|
|
|
send is going on will halt the processor until the send is
|
|
|
|
|
completed. A read will receive any byte that was received
|
|
|
|
|
by the UART since the last read, or 0xFFFFFFFF when none
|
|
|
|
|
was. There is no receive buffer, so it's possible to miss
|
|
|
|
|
data if you don't poll frequently enough.
|
|
|
|
|
The debug UART is always configured as 8N1. */
|
|
|
|
|
#define UART_DATA_REG 0x00</code></pre>
|
|
|
|
|
<p><tt>mach_defines.h</tt>, Hackaday 2019 Con Badge</p>
|
2020-01-12 06:16:08 +00:00
|
|
|
|
<aside class="notes">
|
2020-01-02 08:45:42 +00:00
|
|
|
|
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,
|
|
|
|
|
and documentation is very free-form. 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.
|
|
|
|
|
</aside>
|
|
|
|
|
</section>
|
|
|
|
|
|
|
|
|
|
<section>
|
|
|
|
|
<h2>About LiteX</h2>
|
2020-01-02 08:47:09 +00:00
|
|
|
|
<ul>
|
2020-01-02 08:45:42 +00:00
|
|
|
|
<li>Hardware Description Language embedded in Python</li>
|
2020-01-02 08:47:09 +00:00
|
|
|
|
<ul>
|
2020-01-02 08:45:42 +00:00
|
|
|
|
<li>Doesn't run Python in hardware!</li>
|
2020-01-02 08:47:09 +00:00
|
|
|
|
</ul>
|
2020-01-02 08:45:42 +00:00
|
|
|
|
<li>Emits Verilog (or Yosys netlists)</li>
|
|
|
|
|
<li>Makes it easy to create a SoC</li>
|
|
|
|
|
<li>Powers the LCA2020 video production setup</li>
|
2020-01-02 08:47:09 +00:00
|
|
|
|
</ul>
|
2020-01-02 08:45:42 +00:00
|
|
|
|
<aside class="notes">
|
|
|
|
|
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. The examples from this talk
|
|
|
|
|
are taken from lxsocdoc and LiteX, but most higher-level hardware description
|
|
|
|
|
languages can take similar approaches to documentation.
|
|
|
|
|
</aside>
|
|
|
|
|
</section>
|
|
|
|
|
|
|
|
|
|
<section>
|
2020-01-02 08:33:07 +00:00
|
|
|
|
<h2>LiteX Primitives</h2>
|
|
|
|
|
<pre><code class="python" data-trim>class GPIOOut(Module, AutoCSR):
|
|
|
|
|
def __init__(self, signal):
|
|
|
|
|
self._out = CSRStorage(len(signal))
|
|
|
|
|
self.comb += signal.eq(self._out.storage)</code></pre>
|
2020-01-02 08:45:42 +00:00
|
|
|
|
<aside class="notes">
|
|
|
|
|
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
|
|
|
|
|
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.
|
|
|
|
|
</aside>
|
|
|
|
|
</section>
|
|
|
|
|
|
|
|
|
|
<section>
|
|
|
|
|
<h4>Case Study: SPI Bitbang Module</h4>
|
|
|
|
|
<pre><code class="python" data-trim>self.bitbang = CSRStorage(4)
|
2020-01-02 06:46:03 +00:00
|
|
|
|
If(self.bitbang.storage[3],
|
2020-01-02 08:33:07 +00:00
|
|
|
|
dq.oe.eq(0)
|
2020-01-02 06:46:03 +00:00
|
|
|
|
).Else(
|
2020-01-02 08:33:07 +00:00
|
|
|
|
dq.oe.eq(1)
|
2020-01-02 06:46:03 +00:00
|
|
|
|
),
|
2020-01-02 06:58:41 +00:00
|
|
|
|
# CPOL=0/CPHA=0 or CPOL=1/CPHA=1 only.
|
|
|
|
|
If(self.bitbang.storage[1],
|
2020-01-02 08:33:07 +00:00
|
|
|
|
self.miso.status.eq(dq.i[1])
|
2020-01-02 06:46:03 +00:00
|
|
|
|
),
|
2020-01-02 06:58:41 +00:00
|
|
|
|
dq.o.eq(
|
2020-01-02 08:33:07 +00:00
|
|
|
|
Cat(self.bitbang.storage[0], Replicate(1, spi_width-1))
|
2020-01-02 06:58:41 +00:00
|
|
|
|
)</code></pre>
|
2020-01-02 08:45:42 +00:00
|
|
|
|
<aside class="notes">
|
|
|
|
|
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.
|
|
|
|
|
|
|
|
|
|
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!
|
|
|
|
|
</aside>
|
|
|
|
|
</section>
|
|
|
|
|
|
|
|
|
|
<section>
|
|
|
|
|
<h2>Aside: Python Docstrings</h2>
|
|
|
|
|
<pre><code class="python" data-trim>def _format_cmd(cmd, spi_width):
|
|
|
|
|
"""
|
|
|
|
|
`cmd` is the read instruction. Since everything is
|
|
|
|
|
transmitted on all dq lines (cmd, adr and data), extend/
|
|
|
|
|
interleave cmd to full pads.dq width even if dq1-dq3 are
|
|
|
|
|
don't care during the command phase: For example, for
|
|
|
|
|
N25Q128, 0xeb is the quad i/o fast read, and extended
|
|
|
|
|
to 4 bits (dq1,dq2,dq3 high) is: 0xfffefeff
|
|
|
|
|
"""
|
|
|
|
|
c = 2**(8*spi_width)-1
|
|
|
|
|
for b in range(8):
|
|
|
|
|
if not (cmd>>b)%2:
|
|
|
|
|
c &= ~(1<<(b*spi_width))
|
|
|
|
|
return c</code></pre>
|
|
|
|
|
<aside class="notes">
|
|
|
|
|
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
|
|
|
|
|
what a Python object is and how to use it. This is almost what we want,
|
|
|
|
|
except once the final SoC is generated we don't really care so much about
|
|
|
|
|
things like constructor arguments or method properties. Documentation for
|
|
|
|
|
the end user is different from documentation for the module developer.
|
|
|
|
|
</aside>
|
|
|
|
|
</section>
|
|
|
|
|
|
|
|
|
|
<section>
|
|
|
|
|
<h2>New Register Definition</h2>
|
|
|
|
|
<pre><code class="python" data-trim>self.bitbang = CSRStorage(4, fields=[
|
2020-01-02 08:33:07 +00:00
|
|
|
|
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
|
2020-01-02 08:45:42 +00:00
|
|
|
|
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">
|
|
|
|
|
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. And so, after
|
|
|
|
|
working with the LiteX creator Florent, we refactored the bitbang
|
|
|
|
|
definition to this.
|
|
|
|
|
</aside>
|
|
|
|
|
</section>
|
|
|
|
|
|
|
|
|
|
<section>
|
|
|
|
|
<h2>Refactored SPI Bitbang</h2>
|
|
|
|
|
<pre><code class="python" data-trim>If(self.bitbang.fields.dir,
|
2020-01-02 08:33:07 +00:00
|
|
|
|
dq.oe.eq(0)
|
2020-01-02 06:58:41 +00:00
|
|
|
|
).Else(
|
2020-01-02 08:33:07 +00:00
|
|
|
|
dq.oe.eq(1)
|
2020-01-02 06:58:41 +00:00
|
|
|
|
),
|
|
|
|
|
# CPOL=0/CPHA=0 or CPOL=1/CPHA=1 only.
|
|
|
|
|
If(self.bitbang.fields.clk,
|
2020-01-02 08:33:07 +00:00
|
|
|
|
self.miso.status.eq(dq.i[1])
|
2020-01-02 06:58:41 +00:00
|
|
|
|
),
|
|
|
|
|
dq.o.eq(
|
2020-01-02 08:33:07 +00:00
|
|
|
|
Cat(self.bitbang.fields.mosi, Replicate(1, spi_width-1))
|
2020-01-02 06:58:41 +00:00
|
|
|
|
)</code></pre>
|
2020-01-02 08:45:42 +00:00
|
|
|
|
<aside class="notes">
|
|
|
|
|
Now the actual bitbang logic looks like this.
|
2020-01-02 06:46:03 +00:00
|
|
|
|
|
2020-01-02 08:45:42 +00:00
|
|
|
|
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.
|
|
|
|
|
</aside>
|
|
|
|
|
</section>
|
2020-01-02 06:46:03 +00:00
|
|
|
|
|
2020-01-02 08:45:42 +00:00
|
|
|
|
<section>
|
2020-01-02 08:33:07 +00:00
|
|
|
|
<h2>Generating a Manual</h2>
|
|
|
|
|
<img data-src="img/lxspi_bitbang.png">
|
2020-01-02 08:45:42 +00:00
|
|
|
|
<aside class="notes">
|
|
|
|
|
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.
|
|
|
|
|
</aside>
|
|
|
|
|
</section>
|
|
|
|
|
|
|
|
|
|
<section>
|
|
|
|
|
<h2>Interrupts</h2>
|
2020-01-02 08:33:07 +00:00
|
|
|
|
<img data-src="img/interrupts.png">
|
2020-01-02 08:45:42 +00:00
|
|
|
|
<aside class="notes">
|
|
|
|
|
We can even extract interrupt information, including which bits inside an
|
|
|
|
|
interrupt register map to which event, and which interrupt number is assigned
|
|
|
|
|
to a given module.
|
|
|
|
|
</aside>
|
|
|
|
|
</section>
|
|
|
|
|
|
2020-01-03 02:00:18 +00:00
|
|
|
|
<section>
|
|
|
|
|
<h2>Undocumented Fields</h2>
|
|
|
|
|
<img data-src="img/timer0-event.png">
|
|
|
|
|
<aside class="notes">
|
|
|
|
|
It turns out that there is enough information that we can extract that
|
|
|
|
|
even undocumented fields are somewhat useful. This is an undocumented
|
|
|
|
|
interrupt register, but lxsocdoc has pulled out the field names and
|
|
|
|
|
is giving useful documentation anyway.
|
|
|
|
|
</aside>
|
|
|
|
|
</section>
|
|
|
|
|
|
2020-01-02 08:45:42 +00:00
|
|
|
|
<section>
|
|
|
|
|
<h2>More Documentation: ModuleDoc</h2>
|
2020-01-02 08:33:07 +00:00
|
|
|
|
<img data-src="img/timer0-doc.png">
|
2020-01-02 08:45:42 +00:00
|
|
|
|
<aside class="notes">
|
|
|
|
|
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. We can take a cue from CSRs themselves, and add module documentation
|
|
|
|
|
in a similar fashion.
|
|
|
|
|
</aside>
|
|
|
|
|
</section>
|
|
|
|
|
|
|
|
|
|
<section>
|
|
|
|
|
<h2>Protocol Documentation</h2>
|
2020-01-02 08:33:07 +00:00
|
|
|
|
<img data-src="img/usb-wishbone.png">
|
2020-01-02 08:45:42 +00:00
|
|
|
|
<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>
|
2020-01-03 02:58:11 +00:00
|
|
|
|
<table>
|
|
|
|
|
<tr>
|
|
|
|
|
<td>
|
|
|
|
|
<ul>
|
|
|
|
|
<li>XML description file</li>
|
|
|
|
|
<li>Interrupt numbers</li>
|
|
|
|
|
<li>Memory layout</li>
|
|
|
|
|
<li>Register definitions</li>
|
|
|
|
|
<li>Register fields</li>
|
|
|
|
|
</ul>
|
|
|
|
|
</td>
|
|
|
|
|
<td>
|
|
|
|
|
<img data-src="img/CMSIS_SVD_Schema_Gen.png">
|
|
|
|
|
<br/><small>Source: keil.com</small>
|
|
|
|
|
</td>
|
|
|
|
|
</tr>
|
|
|
|
|
</table>
|
2020-01-02 08:45:42 +00:00
|
|
|
|
<aside class="notes">
|
2020-01-13 00:16:00 +00:00
|
|
|
|
System View Description.
|
2020-01-02 08:45:42 +00:00
|
|
|
|
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
|
|
|
|
|
defines various aspects about a chip, including memory layout, interrupt map,
|
|
|
|
|
and register sets. SVD includes information such as default values and field
|
|
|
|
|
bits, all information we have thanks to the introspectability of Python.
|
|
|
|
|
</aside>
|
|
|
|
|
</section>
|
|
|
|
|
|
|
|
|
|
<section>
|
|
|
|
|
<h2>SVD2Rust: Generating Safe Accessors</h2>
|
2020-01-02 13:46:46 +00:00
|
|
|
|
<pre><code class="rust">fn init(&mut self) {
|
|
|
|
|
self.registers
|
|
|
|
|
.ctrl
|
|
|
|
|
.write(|w| w.exe().bit(true).curren().bit(true).rgbleden().bit(true));
|
|
|
|
|
self.write(LEDDEN | FR250 | QUICK_STOP, LedRegister::LEDDCR0);
|
|
|
|
|
|
|
|
|
|
// Set clock register to 12 MHz / 64 kHz - 1
|
|
|
|
|
self.write(((12_000_000u32 / 64_000u32) - 1) as u8, LedRegister::LEDDBR);
|
|
|
|
|
|
|
|
|
|
self.write(
|
|
|
|
|
BREATHE_ENABLE | BREATHE_MODE_FIXED | breathe_rate_ms(128),
|
|
|
|
|
LedRegister::LEDDBCRR,
|
|
|
|
|
);
|
|
|
|
|
}</code></pre>
|
2020-01-02 08:45:42 +00:00
|
|
|
|
<aside class="notes">
|
|
|
|
|
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 into a Rust Peripheral Access Crate (PAC) using `SVD2Rust`, giving us an
|
|
|
|
|
easy way to safely access all peripherals on a device.
|
|
|
|
|
</aside>
|
|
|
|
|
</section>
|
|
|
|
|
|
|
|
|
|
<section>
|
|
|
|
|
<h2>Renode: Fancy Register Logging</h2>
|
2020-01-03 02:58:11 +00:00
|
|
|
|
<table width="100%">
|
2020-01-03 03:07:02 +00:00
|
|
|
|
<tr style="padding-right: 0px; padding-left: 0px;">
|
|
|
|
|
<td width="75%" style="padding-right: 0px; padding-left: 0px; text-align: center">
|
|
|
|
|
<img style="padding-right: 0px; padding-left: 0px;" width="100%" data-src="img/renode-debug.png"/>
|
2020-01-03 02:58:11 +00:00
|
|
|
|
</td>
|
2020-01-03 03:07:02 +00:00
|
|
|
|
<td style="padding-right: 0px; padding-left: 0px; text-align: center">
|
2020-01-03 02:58:11 +00:00
|
|
|
|
<img data-src="img/renode-ui-tall.png">
|
|
|
|
|
</td>
|
|
|
|
|
</tr>
|
|
|
|
|
</table>
|
2020-01-02 08:45:42 +00:00
|
|
|
|
<aside class="notes">
|
|
|
|
|
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
|
|
|
|
|
what a program is doing.
|
|
|
|
|
</aside>
|
|
|
|
|
</section>
|
|
|
|
|
|
|
|
|
|
<section>
|
|
|
|
|
<h2>Benefits of Higher Level Languages</h2>
|
2020-01-03 02:58:11 +00:00
|
|
|
|
<ul>
|
|
|
|
|
<li>Greater code reuse</li>
|
|
|
|
|
<li>More hardware description</li>
|
|
|
|
|
<li>Automatic document generation</li>
|
|
|
|
|
<li>Automatic SVD</li>
|
|
|
|
|
</ul>
|
2020-01-02 08:45:42 +00:00
|
|
|
|
<aside class="notes">
|
|
|
|
|
By using a higher level language, we are able to describe the hardware
|
|
|
|
|
in greater detail than if we used Verilog or VHDL. We can add additional
|
|
|
|
|
fields to our register definition fields to provide nice, human-readable
|
|
|
|
|
documentation. This also allows us to generate machine-readable formats
|
|
|
|
|
such as SVD, which opens up a whole world of software.
|
|
|
|
|
</aside>
|
|
|
|
|
</section>
|
|
|
|
|
|
|
|
|
|
<section>
|
|
|
|
|
<h2>Documentation helps others</h2>
|
2020-01-03 02:58:11 +00:00
|
|
|
|
<h2 class="fragment">Documentation helps you</h2>
|
2020-01-02 08:45:42 +00:00
|
|
|
|
<aside class="notes">
|
|
|
|
|
Documenting your hardware is important because it is necessary for you to
|
|
|
|
|
write software that interfaces with it today, and it helps you work with
|
|
|
|
|
others when it comes time to share your design with the world. By
|
|
|
|
|
properly documenting various fields within your module, you make it easier
|
|
|
|
|
on yourself to interact with today, and you make it easier to let others
|
|
|
|
|
get up to speed in the future. By documenting your hardware, you're helping
|
|
|
|
|
to pay it forward.
|
|
|
|
|
</aside>
|
|
|
|
|
</section>
|
|
|
|
|
|
|
|
|
|
<section>
|
|
|
|
|
<h2>Thank you</h2>
|
|
|
|
|
<h3>Questions</h3>
|
2020-01-13 01:23:14 +00:00
|
|
|
|
<div>
|
|
|
|
|
<a href="https://github.com/litex-hub/lxsocdoc">https://github.com/litex-hub/lxsocdoc</a>
|
|
|
|
|
<div><small>(t.xobs.io/lxsocdoc)</small></div>
|
|
|
|
|
</div>
|
|
|
|
|
<div>
|
|
|
|
|
</div>
|
2020-01-02 08:45:42 +00:00
|
|
|
|
</section>
|
|
|
|
|
</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.
|
2020-01-02 12:58:02 +00:00
|
|
|
|
width: "100%",
|
2020-01-02 08:45:42 +00:00
|
|
|
|
height: 700,
|
|
|
|
|
|
|
|
|
|
// Factor of the display size that should remain empty around the content
|
|
|
|
|
margin: 0.1,
|
|
|
|
|
|
|
|
|
|
multiplex: {
|
|
|
|
|
url: 'https://p.xobs.io/',
|
2020-01-10 06:34:24 +00:00
|
|
|
|
id: '17b0ef733e56a4aa',
|
2020-01-02 08:45:42 +00:00
|
|
|
|
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>
|
2020-01-02 03:01:08 +00:00
|
|
|
|
</body>
|
2012-03-24 16:48:16 +00:00
|
|
|
|
|
2012-08-04 04:33:27 +00:00
|
|
|
|
</html>
|