814 lines
23 KiB
HTML
814 lines
23 KiB
HTML
<!doctype html>
|
|
<html>
|
|
|
|
<head>
|
|
<meta charset="utf-8">
|
|
|
|
<title>Fomu: An FPGA in your USB Port</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/teardown19.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">
|
|
<div class="url">Slides: <a href="https://p.xobs.io/camp19/">p.xobs.io/camp19</a> Software: <a
|
|
href="https://fomu.im/camp19">fomu.im/camp19</a></div>
|
|
<span class="theme">CCC Camp 2019</span><span class="hashtag"> | #CCCamp</span><span class="twitter"> |
|
|
@tomu_im</span>
|
|
</div>
|
|
<div class="slides">
|
|
<section>
|
|
<p>
|
|
Software is available on the USB drive marked "Fomu Workshop"
|
|
</p>
|
|
<p>
|
|
Or, download software from <a href="https://fomu.im/camp19">fomu.im/camp19</a>
|
|
</p>
|
|
</section>
|
|
|
|
<section data-background-image="css/theme/teardown2019-title-bg-transparent.svg">
|
|
<h1>Fomu: An FPGA in your USB Port</h1>
|
|
<h4>A whirlwind introduction to Fomu; a workshop in three levels</h4>
|
|
<p align="right">
|
|
<small>Sean "xobs" Cross - <a href="https://xobs.io/">https://xobs.io/</a> - @xobs</small>
|
|
<small>Tim "mithro" Ansell - <a
|
|
href="https://github.com/timvideos/litex-buildenv/wiki/">https://github.com/timvideos/litex-buildenv/wiki/</a>
|
|
- @mithro</small>
|
|
</p>
|
|
</section>
|
|
|
|
<section>
|
|
<h2>Levels of Fomu</h2>
|
|
<p>
|
|
Fomu aims to be accessable on three levels:
|
|
<ol>
|
|
<li>Python / Interpreter</li>
|
|
<li>RISC-V / C</li>
|
|
<li>FPGA / HDL</li>
|
|
</ol>
|
|
</p>
|
|
<aside class="notes">
|
|
The overarching idea behind Fomu is to take a top-down approach to hardware design. Start at
|
|
something familiar, such as Python, and keep drilling down until you are no longer interested in
|
|
going further.
|
|
</aside>
|
|
</section>
|
|
|
|
<section>
|
|
<h2>Workshop Outline</h2>
|
|
<ol>
|
|
<li>What do I need to get started?</li>
|
|
<li>What is an FPGA, and what is Fomu?</li>
|
|
<li>Working with Fomu using Python, RISC-V, and HDL</li>
|
|
</ol>
|
|
<aside class="notes">
|
|
Broadly, this workshop will cover three parts: What do you need to get started with Fomu, what is an
|
|
FPGA and why is Fomu special, and finally how to work with Fomu at three different levels.
|
|
</aside>
|
|
</section>
|
|
|
|
<section>
|
|
<section>
|
|
<h2>What do I need to get started?</h2>
|
|
<ol>
|
|
<li>DFU utilities</li>
|
|
<li>Serial console</li>
|
|
<li>RISC-V toolchain</li>
|
|
<li>FPGA Toolchain</li>
|
|
<li>Python 3</li>
|
|
</ol>
|
|
<aside class="notes">
|
|
You require all of the software on this list. This software is provided on the USB drive that's
|
|
provided, or you can get them from <a
|
|
href="https://github.com/im-tomu/fomu-toolchain/releases">https://github.com/im-tomu/fomu-toolchain/releases</a>.
|
|
</aside>
|
|
</section>
|
|
</section>
|
|
|
|
<section>
|
|
<section>
|
|
<h2>What is an FPGA?</h2>
|
|
<img data-src="img/ice40-lut.png" alt="SB_LUT4">
|
|
<aside class="notes">
|
|
An FPGA is an array of gates that's field-programmable. A more useful definition might be "a
|
|
chip you can reconfigure". Most chips are collections of transistors that take two inputs and
|
|
have one output. FPGAs have collections of transistors that look like this -- they take multiple
|
|
inputs and produce multiple outputs. On Fomu, the basic building block is a 4-input 1-output
|
|
lookup table called an "LC4". These are so important to FPGAs that the part number usually
|
|
contains how many LUTs there are. The Fomu has a UP5K, which has about 5000 LUTs. The NeTV had
|
|
an LX9, which had 9000 LUTs. The NeTV2 has an XC7A35T, which has 35000 LUTs.
|
|
</aside>
|
|
</section>
|
|
|
|
<section>
|
|
<h2>What is an FPGA?</h2>
|
|
<table style="transform: scale(.80) translate(-15%)">
|
|
<tr>
|
|
<th></th>
|
|
<th>0</th>
|
|
<th>1</th>
|
|
<th>2</th>
|
|
<th>3</th>
|
|
<th>4</th>
|
|
<th>5</th>
|
|
<th>6</th>
|
|
<th>7</th>
|
|
<th>8</th>
|
|
<th>9</th>
|
|
<th>10</th>
|
|
<th>11</th>
|
|
<th>12</th>
|
|
<th>13</th>
|
|
<th>14</th>
|
|
<th>15</th>
|
|
</tr>
|
|
<tr>
|
|
<td>IO0</td>
|
|
<td>0</td>
|
|
<td>0</td>
|
|
<td>0</td>
|
|
<td>0</td>
|
|
<td>0</td>
|
|
<td>0</td>
|
|
<td>0</td>
|
|
<td>0</td>
|
|
<td>1</td>
|
|
<td>1</td>
|
|
<td>1</td>
|
|
<td>1</td>
|
|
<td>1</td>
|
|
<td>1</td>
|
|
<td>1</td>
|
|
<td>1</td>
|
|
</tr>
|
|
<tr>
|
|
<td>IO1</td>
|
|
<td>0</td>
|
|
<td>0</td>
|
|
<td>0</td>
|
|
<td>0</td>
|
|
<td>1</td>
|
|
<td>1</td>
|
|
<td>1</td>
|
|
<td>1</td>
|
|
<td>0</td>
|
|
<td>0</td>
|
|
<td>0</td>
|
|
<td>0</td>
|
|
<td>1</td>
|
|
<td>1</td>
|
|
<td>1</td>
|
|
<td>1</td>
|
|
</tr>
|
|
<tr>
|
|
<td>IO2</td>
|
|
<td>0</td>
|
|
<td>0</td>
|
|
<td>1</td>
|
|
<td>1</td>
|
|
<td>0</td>
|
|
<td>0</td>
|
|
<td>1</td>
|
|
<td>1</td>
|
|
<td>0</td>
|
|
<td>0</td>
|
|
<td>1</td>
|
|
<td>1</td>
|
|
<td>0</td>
|
|
<td>0</td>
|
|
<td>1</td>
|
|
<td>1</td>
|
|
</tr>
|
|
<tr>
|
|
<td>IO3</td>
|
|
<td>0</td>
|
|
<td>1</td>
|
|
<td>0</td>
|
|
<td>1</td>
|
|
<td>0</td>
|
|
<td>1</td>
|
|
<td>0</td>
|
|
<td>1</td>
|
|
<td>0</td>
|
|
<td>1</td>
|
|
<td>0</td>
|
|
<td>1</td>
|
|
<td>0</td>
|
|
<td>1</td>
|
|
<td>0</td>
|
|
<td>1</td>
|
|
</tr>
|
|
<tr>
|
|
<td>O</td>
|
|
<td>?</td>
|
|
<td>?</td>
|
|
<td>?</td>
|
|
<td>?</td>
|
|
<td>?</td>
|
|
<td>?</td>
|
|
<td>?</td>
|
|
<td>?</td>
|
|
<td>?</td>
|
|
<td>?</td>
|
|
<td>?</td>
|
|
<td>?</td>
|
|
<td>?</td>
|
|
<td>?</td>
|
|
<td>?</td>
|
|
<td>?</td>
|
|
</tr>
|
|
</table>
|
|
<aside class="notes">
|
|
A LUT is a lookup table. The value of the output depends on the value of all the inputs. You can
|
|
make arbitrary boolean logic here. For example, we could make a LUT that performs the logical
|
|
AND of all the inputs, and set it so that it only outputs a "1" if all of the inputs are 1. Or
|
|
we can make a NAND gate by taking the inverse. Each one of those 5000 LUTs in Fomu has a truth
|
|
table like this that it evaluates in real time.
|
|
</aside>
|
|
</section>
|
|
|
|
<section>
|
|
<h2>What is an FPGA?</h2>
|
|
<pre><code class="verilog" data-trim>
|
|
module example (output reg [0:5] Q, input C);
|
|
reg [0:8] counter;
|
|
always @(posedge C)
|
|
begin
|
|
counter <= counter + 1'b1;
|
|
Q = counter[7] ^ counter[5] | counter<<2;
|
|
end
|
|
endmodule
|
|
</code></pre>
|
|
<img class="fragment" data-src="img/verilog-synthesis.png" alt="Verilog Synthesis">
|
|
<aside class="notes">
|
|
It gets really tedious to be thinking about lookup tables all the time, so humans created
|
|
programming languages to do it for them. This is an example of Verilog code. It makes a simple
|
|
counter that outputs the xor of some values.
|
|
|
|
In order to turn this Verilog code into actual LUTs, we run it through a synthesizer. Much like
|
|
how a compiler turns programming language into CPU opcodes, a synthesizer turns Verilog code
|
|
into lookup tables
|
|
</aside>
|
|
</section>
|
|
|
|
<section>
|
|
<h2>About the ICE40UP5K</h2>
|
|
<ol>
|
|
<li>5280 4-input LUTs (LC)</li>
|
|
<li>16 kilobytes BRAM</li>
|
|
<li class="fragment highlight-blue">128 kilobytes "SPRAM"</li>
|
|
<li>Current-limited 3-channel LED driver</li>
|
|
<li>2x I2C and 2x SPI</li>
|
|
<li>8 16-bit DSP units</li>
|
|
<li class="fragment highlight-blue">Warmboot capability</li>
|
|
<li class="fragment highlight-blue">Open toolchain</li>
|
|
</ol>
|
|
</section>
|
|
|
|
<section>
|
|
<h2>What is Fomu?</h2>
|
|
<ul>
|
|
<li>ICE40UP5K</li>
|
|
<li>2MB QSPI flash memory</li>
|
|
<li>Four edge-plated pads</li>
|
|
<li>ESD protection</li>
|
|
<li>USB implemented in HDL</li>
|
|
<li class="fragment highlight-blue">Fits in your USB port</li>
|
|
</ul>
|
|
<aside class="notes">
|
|
Fomu is an FPGA that fits in your USB port. It has foru buttons, 2 MB of SPI flash, an RGB LED,
|
|
and an ICE40UP5K with 5280 LCs. It also has 128 kB of dedicated RAM, not counting the block RAM.
|
|
|
|
Unlike many other PCBs, Fomu does not have a separate USB controller chip. This means that any
|
|
projects that want to use the USB port must include a USB softcore.
|
|
</aside>
|
|
</section>
|
|
|
|
<section>
|
|
<h2>Fomu Block Design Diagram</h2>
|
|
<img data-src="img/fomu-block-diagram.png" alt="Fomu block diagram">
|
|
</section>
|
|
|
|
<section>
|
|
<h2>Fomu SPI Flash Layout</h2>
|
|
<img data-src="img/fomu-memory-layout.png" alt="Fomu memory layout">
|
|
<!-- <ol>
|
|
<li>Bootloader</li>
|
|
<li>Recovery</li>
|
|
<li>Magic constants</li>
|
|
<li>Interpreters</li>
|
|
<li>Updates</li>
|
|
</ol> -->
|
|
</section>
|
|
</section>
|
|
|
|
<section>
|
|
<section>
|
|
<h2>Working with Fomu</h2>
|
|
</section>
|
|
|
|
<section>
|
|
<h2>FAT Bootloader</h2>
|
|
<ul>
|
|
<li>Presents itself as a USB disk</li>
|
|
<li>Drag and drop files to program</li>
|
|
<li>Multiple interpreter support</li>
|
|
</ul>
|
|
<div>
|
|
<img data-src="img/under-construction.gif" class="fragment">
|
|
</div>
|
|
</section>
|
|
|
|
<section>
|
|
<h2>"fail safe" bootloader</h2>
|
|
Device Firmware Update - <strong>DFU</strong>
|
|
</section>
|
|
|
|
<section>
|
|
<h2>Uploading Code</h2>
|
|
<pre><code>$ dfu-util -l
|
|
Found DFU: [1209:5bf0] name="Fomu Hacker running DFU Bootloader v1.8.8"
|
|
$ dfu-util -D program.bin
|
|
Download [========= ] 36% 38912 bytes
|
|
Download done.
|
|
$ dfu-util -l
|
|
$</code></pre>
|
|
</section>
|
|
</section>
|
|
|
|
<section>
|
|
<section>
|
|
<h2>Python / Interpreted</h2>
|
|
<ol>
|
|
<li><strong>Goal:</strong> Multiple interpreters, auto-reload, USB disk interface</li>
|
|
<li><strong>Now:</strong> MicroPython binary</li>
|
|
</ol>
|
|
</section>
|
|
|
|
<section>
|
|
<h2>Loading Programs onto Fomu</h2>
|
|
<pre><code>
|
|
$ dfu-util -l
|
|
Found DFU: [1209:5bf0] name="Fomu DFU Bootloader v1.8.8"
|
|
$ dfu-util -e # Boot current program
|
|
$ dfu-util -D new-image.dfu # Load new program</code></pre>
|
|
<h3 class="fragment">u<code>5b f0</code>mu</h3>
|
|
</section>
|
|
|
|
<section>
|
|
<h2>Loading MicroPython</h2>
|
|
<pre><code>$ dfu-util -D micropython-fomu.dfu</code></pre>
|
|
</section>
|
|
|
|
<section>
|
|
<h2>Connecting via serial</h2>
|
|
<pre class="fragment"><code>screen /dev/cu.usbserial*</code></pre>
|
|
<pre class="fragment"><code>screen /dev/ttyACM*</code></pre>
|
|
<pre class="fragment"><code>Tera Term</code></pre>
|
|
<pre class="fragment"><code>MicroPython v1.10-296-g0a5a77a on 2019-06-18; fomu with vexriscv
|
|
>>></code></pre>
|
|
</section>
|
|
|
|
<section>
|
|
<h2>Interacting with Fomu</h2>
|
|
<pre><code class="python" data-trim>
|
|
>>> import fomu
|
|
>>> rgb = fomu.rgb()
|
|
>>> rgb.mode("error")
|
|
>>>
|
|
</code></pre>
|
|
</section>
|
|
|
|
<section>
|
|
<h2>Read SPI ID</h2>
|
|
<pre><code class="python" data-trim>
|
|
>>> spi = fomu.spi()
|
|
>>> hex(spi.id())
|
|
'0xc2152815'
|
|
>>>
|
|
</code></pre>
|
|
</section>
|
|
|
|
<section>
|
|
<h2>Memory-Mapped Registers</h2>
|
|
<pre><code class="cpp">#define CSR_VERSION_MAJOR_ADDR 0xe0007000
|
|
#define CSR_VERSION_MINOR_ADDR 0xe0007004
|
|
#define CSR_VERSION_REVISION_ADDR 0xe0007008</code></pre>
|
|
<pre class="fragment"><code class="python">>>> import machine
|
|
>>> machine.mem32[0xe0007000]
|
|
1
|
|
>>></code></pre>
|
|
</section>
|
|
|
|
<section>
|
|
<h2>RGB LED Driver reference</h2>
|
|
<img data-src="img/ice40-ledd.png" alt="ICE40 LEDD registers">
|
|
<pre class="fragment"><code class="python" data-trim>>>> rgb.write_raw(0b0001, 255)
|
|
>>> rgb.write_raw(0b1010, 14)
|
|
>>> rgb.write_raw(0b1011, 1)
|
|
>>> </code></pre>
|
|
</section>
|
|
|
|
<section>
|
|
<h2>Future Work</h2>
|
|
<ul>
|
|
<li>CircuitPython</li>
|
|
<li>eLua</li>
|
|
<li>Espurino?</li>
|
|
</ul>
|
|
</section>
|
|
</section>
|
|
<section>
|
|
<section>
|
|
<h2>RISC-V</h2>
|
|
</section>
|
|
|
|
<section>
|
|
<h2>LiteX Model</h2>
|
|
<img data-src="img/litex-design.png" alt="LiteX Design">
|
|
</section>
|
|
|
|
<section>
|
|
<h2>Wishbone Bridge</h2>
|
|
<img data-src="img/wishbone-usb-debug-bridge.png" alt="Wishbone bridge">
|
|
</section>
|
|
|
|
<section>
|
|
<h2>CPU is Optional</h2>
|
|
<ul>
|
|
<li>Multiple CPUs available</li>
|
|
<li>
|
|
<ul>
|
|
<li>VexRiscv</li>
|
|
<li>picorv32</li>
|
|
<li>lm32</li>
|
|
<li>...</li>
|
|
</ul>
|
|
</li>
|
|
<li>Also works just fine with no CPU</li>
|
|
</ul>
|
|
</section>
|
|
|
|
<section>
|
|
<h2>CSR Access</h2>
|
|
<pre><code class="cpp">#define CSR_VERSION_MAJOR_ADDR 0xe0007000
|
|
#define CSR_VERSION_MAJOR_SIZE 1
|
|
#define CSR_VERSION_MINOR_ADDR 0xe0007004
|
|
#define CSR_VERSION_MINOR_SIZE 1
|
|
#define CSR_VERSION_REVISION_ADDR 0xe0007008
|
|
#define CSR_VERSION_REVISION_SIZE 1
|
|
#define CSR_VERSION_GITREV_ADDR 0xe000700c
|
|
#define CSR_VERSION_GITREV_SIZE 4
|
|
#define CSR_VERSION_GITEXTRA_ADDR 0xe000701c
|
|
#define CSR_VERSION_GITEXTRA_SIZE 2
|
|
</code></pre>
|
|
Excerpt from <code>csr.h</code>
|
|
</section>
|
|
|
|
<section>
|
|
<h2>Reading CPU Version</h2>
|
|
<pre><code class="sh">$ wishbone-tool --pid 0x5bf0 0xe0007000
|
|
Value at e0007000: 00000001
|
|
$ wishbone-tool --pid 0x5bf0 0xe0007004
|
|
Value at e0007004: 00000008
|
|
$ wishbone-tool --pid 0x5bf0 0xe0007008
|
|
Value at e0007008: 00000001</code></pre>
|
|
</section>
|
|
|
|
<section>
|
|
<h2>Interacting with LEDD directly</h2>
|
|
<img data-src="img/ice40-ledd.png" alt="ICE40 LEDD registers">
|
|
<pre class="fragment"><code class="cpp">#define CSR_RGB_DAT_ADDR 0xe0006800L
|
|
#define CSR_RGB_ADDR_ADDR 0xe0006804L</code></pre>
|
|
<pre class="fragment"><code>$ wishbone-tool --pid 0x5bf0 0xe0006804 1
|
|
$ wishbone-tool --pid 0x5bf0 0xe0006800 0xff</code></pre>
|
|
</section>
|
|
|
|
<section>
|
|
<h2>Writing RISC-V Code</h2>
|
|
<pre><code>$ make
|
|
CC ./src/main.c main.o
|
|
CC ./src/rgb.c rgb.o
|
|
CC ./src/time.c time.o
|
|
AS ./src/crt0-vexriscv.S crt0-vexriscv.o
|
|
LD riscv-blink.elf
|
|
OBJCOPY riscv-blink.bin
|
|
IHEX riscv-blink.ihex
|
|
$ </code></pre>
|
|
<p>
|
|
From <code>riscv-blink</code> directory in <code>teardown2019-workshop</code>
|
|
</p>
|
|
</section>
|
|
|
|
<section>
|
|
<h2>Modifying RISC-V Code</h2>
|
|
<pre><code class="diff">--- a/riscv-blink/src/main.c
|
|
+++ b/riscv-blink/src/main.c
|
|
@@ -38,6 +38,7 @@ void isr(void) {
|
|
void main(void) {
|
|
rgb_init();
|
|
irq_setie(0);
|
|
+ rgb_write((100000/64000)-1, LEDDBR);
|
|
int i = 0;
|
|
while (1) {
|
|
i++;</code></pre>
|
|
</section>
|
|
|
|
<section>
|
|
<h2>Other RISC-V Programs</h2>
|
|
riscv-usb-cdcacm: echo characters back after adding 1
|
|
</section>
|
|
</section>
|
|
|
|
<section>
|
|
<section>
|
|
<h2>Hardware Description Language</h2>
|
|
</section>
|
|
|
|
<section>
|
|
<h2>Yosys and NextPNR</h2>
|
|
<ul>
|
|
<li>Timing Driven!</li>
|
|
</ul>
|
|
<pre><code>Max frequency for clock 'clk12': 24.63 MHz (PASS at 12.00 MHz)
|
|
Max frequency for clock 'clk48_1': 60.66 MHz (PASS at 48.00 MHz)
|
|
Max frequency for clock 'clkraw': 228.05 MHz (PASS at 48.00 MHz)</code></pre>
|
|
</section>
|
|
|
|
<section>
|
|
<h2>Blinking an LED</h2>
|
|
<pre><code>$ make FOMU_REV=evt
|
|
...
|
|
20 warnings, 0 errors
|
|
PACK blink.bin
|
|
Built 'blink' for Fomu evt1
|
|
$ dfu-util -D blink.bin</code></pre>
|
|
</section>
|
|
|
|
<section>
|
|
<h2>LiteX and MiGen</h2>
|
|
<ol>
|
|
<li>Define hardware in Python</li>
|
|
<li>Evaluate Python to produce netlist</li>
|
|
<li>Synthesize netlist to FPGA</li>
|
|
</ol>
|
|
</section>
|
|
|
|
<section>
|
|
<h2>lxbuildenv.py</h2>
|
|
<ol>
|
|
<li>Python environment using native interpreter</li>
|
|
<li>Very stable, good for hardware projects</li>
|
|
<li>Should work with system Python</li>
|
|
<li>Runs on Linux, Windows, Raspberry Pi</li>
|
|
</ol>
|
|
</section>
|
|
|
|
<section>
|
|
<h2>Why do we need a CPU?</h2>
|
|
<img data-src="img/litex-design.png" alt="LiteX Design">
|
|
</section>
|
|
|
|
<section>
|
|
<h2>What if we remove the CPU?</h2>
|
|
<ul>
|
|
<li>Workshop project has no CPU</li>
|
|
<li>DummyUsb module automatically enumerates</li>
|
|
<li>Wishbone Debug Bridge still accessible</li>
|
|
</ul>
|
|
</section>
|
|
|
|
<section>
|
|
<h2>Build Workshop Module</h2>
|
|
<pre><code>$ python3 workshop.py --placer heap
|
|
...
|
|
5 warnings, 0 errors
|
|
$ </code></pre>
|
|
</section>
|
|
|
|
<section>
|
|
<h2>Load onto Fomu</h2>
|
|
<pre><code>$ dfu-util -D build/gateware/top.bin
|
|
Download [=========================] 100% 104090 bytes
|
|
Download done.
|
|
$ </code></pre>
|
|
</section>
|
|
|
|
<section>
|
|
<h2>Write a value to RAM</h2>
|
|
<pre><code>$ wishbone-tool --pid 0x5bf0 0x10000000
|
|
Value at 10000000: 0baf801e
|
|
$ wishbone-tool --pid 0x5bf0 0x10000000 0x12345678
|
|
$ wishbone-tool --pid 0x5bf0 0x10000000
|
|
Value at 10000000: 12345678
|
|
$ </code></pre>
|
|
</section>
|
|
|
|
<section>
|
|
<h2>Adding Hardware</h2>
|
|
<img data-src="img/ice40-rgb.jpg" alt="Schematic of RGB block">
|
|
</section>
|
|
|
|
<section>
|
|
<h2>Technology Library Reference</h2>
|
|
<pre><code class="verilog">// Verilog Instantiation
|
|
SB_RGBA_DRV RGBA_DRIVER (
|
|
.CURREN(ENABLE_CURR),
|
|
.RGBLEDEN(ENABLE_RGBDRV),
|
|
.RGB0PWM(RGB0),
|
|
.RGB1PWM(RGB1),
|
|
.RGB2PWM(RGB2),
|
|
.RGB0(LED0),
|
|
.RGB1(LED1),
|
|
.RGB2(LED2)
|
|
);
|
|
defparam RGBA_DRIVER.CURRENT_MODE = "0b0";
|
|
defparam RGBA_DRIVER.RGB0_CURRENT = "0b111111";
|
|
defparam RGBA_DRIVER.RGB1_CURRENT = "0b111111" ;
|
|
defparam RGBA_DRIVER.RGB2_CURRENT = "0b111111";</code></pre>
|
|
<p>SBTICETechnologyLibrary201504.pdf page 147</p>
|
|
</section>
|
|
<section>
|
|
<h2>RGB Block</h2>
|
|
<pre><code class="python" style="font-size: 18px; line-height: 22px">class FomuRGB(Module, AutoCSR):
|
|
def __init__(self, pads):
|
|
self.output = CSRStorage(3)
|
|
self.specials += Instance("SB_RGBA_DRV",
|
|
i_CURREN = 0b1,
|
|
i_RGBLEDEN = 0b1,
|
|
i_RGB0PWM = self.output.storage[0],
|
|
i_RGB1PWM = self.output.storage[1],
|
|
i_RGB2PWM = self.output.storage[2],
|
|
o_RGB0 = pads.r,
|
|
o_RGB1 = pads.g,
|
|
o_RGB2 = pads.b,
|
|
p_CURRENT_MODE = "0b1",
|
|
p_RGB0_CURRENT = "0b000011",
|
|
p_RGB1_CURRENT = "0b000011",
|
|
p_RGB2_CURRENT = "0b000011",
|
|
)</code></pre>
|
|
</section>
|
|
|
|
<section>
|
|
<h2>Instantiating FomuRGB</h2>
|
|
<pre><code class="diff">@@ -55,6 +75,10 @@ class BaseSoC(SoCCore):
|
|
with_ctrl=False,
|
|
**kwargs)
|
|
|
|
+ # Add the LED driver block
|
|
+ led_pads = platform.request("rgb_led")
|
|
+ self.submodules.rgb = FomuRGB(led_pads)
|
|
+
|
|
# UP5K has single port RAM....
|
|
# Use this as CPU RAM.
|
|
spram_size = 128*1024</code></pre>
|
|
</section>
|
|
|
|
<section>
|
|
<h2>Interacting with the CSR</h2>
|
|
<pre><code>csr_register,rgb_output,0xe0006800,1,rw</code></pre>
|
|
<p>From <code>test/csr.csv</code></p>
|
|
</section>
|
|
|
|
<section>
|
|
<h2>VexRiscv</h2>
|
|
</section>
|
|
</section>
|
|
|
|
<section>
|
|
<h2>Thank you</h2>
|
|
<h2>Lunch Time!</h2>
|
|
</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.
|
|
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: 'cbd6556886c2825d',
|
|
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>
|
|
|
|
</html> |