Skip to content

Instantly share code, notes, and snippets.

@expipiplus1
Created May 10, 2018 10:56
Show Gist options
  • Save expipiplus1/d3a5e36e2af7e2fbfc5e3a280e9549f9 to your computer and use it in GitHub Desktop.
Save expipiplus1/d3a5e36e2af7e2fbfc5e3a280e9549f9 to your computer and use it in GitHub Desktop.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="generator" content="pandoc">
<meta name="author" content="Joe Hermaszewski">
<title>FPGA Programming with Clash</title>
<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, minimal-ui">
<link rel="stylesheet" href="http://cdn.rawgit.com/hakimel/reveal.js/3.5.0//css/reveal.css">
<style type="text/css">
code{white-space: pre-wrap;}
span.smallcaps{font-variant: small-caps;}
span.underline{text-decoration: underline;}
div.column{display: inline-block; vertical-align: top; width: 50%;}
</style>
<style type="text/css">
a.sourceLine { display: inline-block; line-height: 1.25; }
a.sourceLine { pointer-events: none; color: inherit; text-decoration: inherit; }
a.sourceLine:empty { height: 1.2em; position: absolute; }
.sourceCode { overflow: visible; }
code.sourceCode { white-space: pre; position: relative; }
div.sourceCode { margin: 1em 0; }
pre.sourceCode { margin: 0; }
@media screen {
div.sourceCode { overflow: auto; }
}
@media print {
code.sourceCode { white-space: pre-wrap; }
a.sourceLine { text-indent: -1em; padding-left: 1em; }
}
pre.numberSource a.sourceLine
{ position: relative; }
pre.numberSource a.sourceLine:empty
{ position: absolute; }
pre.numberSource a.sourceLine::before
{ content: attr(data-line-number);
position: absolute; left: -5em; text-align: right; vertical-align: baseline;
border: none; pointer-events: all;
-webkit-touch-callout: none; -webkit-user-select: none;
-khtml-user-select: none; -moz-user-select: none;
-ms-user-select: none; user-select: none;
padding: 0 4px; width: 4em;
color: #aaaaaa;
}
pre.numberSource { margin-left: 3em; border-left: 1px solid #aaaaaa; padding-left: 4px; }
div.sourceCode
{ }
@media screen {
a.sourceLine::before { text-decoration: underline; }
}
code span.al { color: #ff0000; font-weight: bold; } /* Alert */
code span.an { color: #60a0b0; font-weight: bold; font-style: italic; } /* Annotation */
code span.at { color: #7d9029; } /* Attribute */
code span.bn { color: #40a070; } /* BaseN */
code span.bu { } /* BuiltIn */
code span.cf { color: #007020; font-weight: bold; } /* ControlFlow */
code span.ch { color: #4070a0; } /* Char */
code span.cn { color: #880000; } /* Constant */
code span.co { color: #60a0b0; font-style: italic; } /* Comment */
code span.cv { color: #60a0b0; font-weight: bold; font-style: italic; } /* CommentVar */
code span.do { color: #ba2121; font-style: italic; } /* Documentation */
code span.dt { color: #902000; } /* DataType */
code span.dv { color: #40a070; } /* DecVal */
code span.er { color: #ff0000; font-weight: bold; } /* Error */
code span.ex { } /* Extension */
code span.fl { color: #40a070; } /* Float */
code span.fu { color: #06287e; } /* Function */
code span.im { } /* Import */
code span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Information */
code span.kw { color: #007020; font-weight: bold; } /* Keyword */
code span.op { color: #666666; } /* Operator */
code span.ot { color: #007020; } /* Other */
code span.pp { color: #bc7a00; } /* Preprocessor */
code span.sc { color: #4070a0; } /* SpecialChar */
code span.ss { color: #bb6688; } /* SpecialString */
code span.st { color: #4070a0; } /* String */
code span.va { color: #19177c; } /* Variable */
code span.vs { color: #4070a0; } /* VerbatimString */
code span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warning */
</style>
<link rel="stylesheet" href="http://cdn.rawgit.com/hakimel/reveal.js/3.5.0//css/theme/beige.css" id="theme">
<!-- 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 ) ? 'http://cdn.rawgit.com/hakimel/reveal.js/3.5.0//css/print/pdf.css' : 'http://cdn.rawgit.com/hakimel/reveal.js/3.5.0//css/print/paper.css';
document.getElementsByTagName( 'head' )[0].appendChild( link );
</script>
<!--[if lt IE 9]>
<script src="http://cdn.rawgit.com/hakimel/reveal.js/3.5.0//lib/js/html5shiv.js"></script>
<![endif]-->
</head>
<body>
<div class="reveal">
<div class="slides">
<section id="title-slide">
<h1 class="title">FPGA Programming with Clash</h1>
<p class="author">Joe Hermaszewski</p>
<p class="date">May 10 2018</p>
</section>
<section class="slide level3">
<ul>
<li>Motivation behind Clash</li>
<li>Basic concepts used</li>
<li>CPU for interpreting a very simple language</li>
</ul>
<aside class="notes">
<p>This is what we are going to discuss</p>
</aside>
</section>
<section><section id="the-motivation" class="title-slide slide level2"><h2>The motivation</h2></section><section class="slide level3">
<blockquote>
<p>HDLs were not developed for use with logic-synthesis tools.</p>
</blockquote>
<p>– Application-Specific Integrated Circuits - June 1997</p>
<aside class="notes">
<p>Basically: VHDL and Verilog are just terrible</p>
<p>Logic synthesis provides a link between an HDL (Verilog or VHDL) and a netlist similarly to the way that a C compiler provides a link between C code and machine language. However, the parallel is not exact. C was developed for use with compilers, but <em>HDLs were not developed for use with logic-synthesis tools</em>.</p>
</aside>
</section><section class="slide level3">
<blockquote>
<p>Both Verilog and VHDL were developed well before the introduction of commercial logic-synthesis software</p>
</blockquote>
<p>– Application-Specific Integrated Circuits - June 1997</p>
<aside class="notes">
<p>Verilog was designed as a simulation language and VHDL was designed as a documentation and description language. <em>Both Verilog and VHDL were developed in the early 1980s, well before the introduction of commercial logic-synthesis software</em>.</p>
</aside>
</section><section class="slide level3">
<blockquote>
<p>The current state of synthesis software is rather like learning a foreign language, and then having to talk to a five-year-old.</p>
</blockquote>
<p>– Application-Specific Integrated Circuits - June 1997</p>
<aside class="notes">
<p>Because these HDLs are now being used for purposes for which they were not intended, the state of the art in logic synthesis falls far short of that for computer-language compilers. Logic synthesis forces designers to use a subset of both Verilog and VHDL. This makes using logic synthesis more difficult rather than less difficult. <em>The current state of synthesis software is rather like learning a foreign language, and then having to talk to a five-year-old.</em></p>
</aside>
</section><section class="slide level3">
<blockquote>
<p>This situation should improve in the next five years, as logic synthesizers mature.</p>
</blockquote>
<p>– Application-Specific Integrated Circuits - June 1997</p>
<aside class="notes">
<p>When talking to a logic-synthesis tool using an HDL, it is necessary to think like hardware, anticipating the netlist that logic synthesis will produce. <em>This situation should improve in the next five years, as logic synthesizers mature.</em></p>
</aside>
</section><section class="slide level3">
<p>It did not improve</p>
<aside class="notes">
<p>I’m sure that nobody here needs convincing that terrible programming languages exist.</p>
<p>As much fun as it would be to keep talking about how much VHDL and Verilog suck I’m here to talk about Clash</p>
</aside>
</section><section class="slide level3">
<ul>
<li>Great type system and inference</li>
<li>Great at abstracting</li>
<li>…</li>
</ul>
<aside class="notes">
<p>Similarly I don’t need to espouse the benefits of Haskell here.</p>
<p>blah blah blah</p>
<p>Wouldn’t it be nice to be able to use Haskell</p>
</aside>
</section><section class="slide level3">
<ul>
<li>Haskell runs on commodity hardware</li>
</ul>
<aside class="notes">
<p>you may not know it but…</p>
<p>This means that we can run our FPGA code on regular CPUs at quite a high level of abstraction,</p>
<p>simulating Gates on the FPGA is very slow, Haskell is pretty fast</p>
<p>space leaks</p>
</aside>
</section></section>
<section><section id="clash-types" class="title-slide slide level2"><h2>Clash types</h2></section><section class="slide level3">
<div class="sourceCode" id="cb1"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb1-1" data-line-number="1"><span class="kw">data</span> <span class="dt">Signal</span> (<span class="ot">domain ::</span> <span class="dt">Domain</span>) a <span class="fu">=</span> a <span class="fu">:-</span> <span class="dt">Signal</span> domain a</a></code></pre></div>
<aside class="notes">
<p>The <code>Signal</code> type is prevalent in Clash code.</p>
<ul>
<li>It maps to a bundle of wires on the hardware</li>
<li>It is an infinite stream of values, one for every cycle in <code>domain</code></li>
<li>It has an <code>Applicative</code> instance</li>
</ul>
</aside>
</section><section class="slide level3">
<ul>
<li><code>pure a</code> is a <code>Signal</code> where the values never change</li>
<li><code>f &lt;*&gt; x</code> zips the two <code>Signals</code> together with <code>$</code></li>
</ul>
<aside class="notes">
<p>This is the applicative instance for Signals</p>
<p>It’s exactly what one would expect for infinite lists</p>
</aside>
</section><section class="slide level3">
<div class="sourceCode" id="cb2"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb2-1" data-line-number="1"><span class="ot">register ::</span> a <span class="ot">-&gt;</span> <span class="dt">Signal</span> domain a <span class="ot">-&gt;</span> <span class="dt">Signal</span> domain a</a></code></pre></div>
<aside class="notes">
<p>This maps (unsurprisingly) to a register (or D-type flip-flop) in the hardware</p>
<p>What this does is to “delay” a signal by one cycle, and on the very first cycle return the first argument of type <code>a</code>.</p>
</aside>
</section><section id="example" class="slide level3">
<h3>Example</h3>
<div class="sourceCode" id="cb3"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb3-1" data-line-number="1"><span class="ot">foo ::</span> <span class="dt">Signal</span> domain <span class="dt">String</span></a>
<a class="sourceLine" id="cb3-2" data-line-number="2">foo <span class="fu">=</span> register <span class="st">&quot;hello&quot;</span> (register <span class="st">&quot;world&quot;</span> (pure <span class="st">&quot;!&quot;</span>))</a></code></pre></div>
<div class="fragment">
<pre><code>&gt;&gt;&gt; sample foo
[&quot;hello&quot;,&quot;world&quot;,&quot;!&quot;,&quot;!&quot;,&quot;!&quot;,&quot;!&quot;,&quot;!&quot;,&quot;!&quot;,&quot;!&quot;,&quot;!&quot;,&quot;!&quot;,...</code></pre>
<aside class="notes">
<p>Strings don’t synthesize to hardware, but we can run this example in ghci</p>
<p>Haskell’s Lazyness makes this work just as one expects</p>
</aside>
</div>
</section><section id="counter-example" class="slide level3">
<h3>Counter Example</h3>
<div class="sourceCode" id="cb5"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb5-1" data-line-number="1"><span class="ot">counter ::</span> <span class="dt">Signal</span> domain <span class="dt">Word32</span></a>
<a class="sourceLine" id="cb5-2" data-line-number="2">counter <span class="fu">=</span> register <span class="dv">0</span> (counter <span class="fu">+</span> <span class="dv">1</span>)</a></code></pre></div>
<div class="fragment">
<pre><code>&gt;&gt;&gt; sample counter
[0,1,2,3,4,5,6,7,8,9..</code></pre>
<aside class="notes">
<p>Every example should have a counter-example!</p>
<p>Note the use of the <code>Num</code> instance for Signals, it’s just the <code>Num</code> functions lifted into an Applicative.</p>
</aside>
</div>
</section><section class="slide level3">
<p>That’s basically it</p>
<aside class="notes">
<p>With these primitives one can construct computation graphs which map sensibly to hardware</p>
</aside>
</section><section id="how-does-it-map-to-hardware" class="slide level3">
<h3>How does it map to hardware</h3>
<ul>
<li>Function application -&gt; combinatorial expressions the hardware (LUTs on FPGAs)</li>
<li>Pattern matching -&gt; muxes</li>
<li>Constants -&gt; constants</li>
</ul>
<aside class="notes">
<p>Everything is a LUT on FPGAs</p>
</aside>
</section><section class="slide level3">
<div class="sourceCode" id="cb7"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb7-1" data-line-number="1">blockRam</a>
<a class="sourceLine" id="cb7-2" data-line-number="2"><span class="ot"> ::</span> <span class="dt">Enum</span> addr</a>
<a class="sourceLine" id="cb7-3" data-line-number="3"> <span class="ot">=&gt;</span> <span class="dt">Vec</span> n a</a>
<a class="sourceLine" id="cb7-4" data-line-number="4"> <span class="co">-- ^ Initial content of the BRAM</span></a>
<a class="sourceLine" id="cb7-5" data-line-number="5"> <span class="ot">-&gt;</span> <span class="dt">Signal</span> dom addr</a>
<a class="sourceLine" id="cb7-6" data-line-number="6"> <span class="co">-- ^ Read address @r@</span></a>
<a class="sourceLine" id="cb7-7" data-line-number="7"> <span class="ot">-&gt;</span> <span class="dt">Signal</span> dom (<span class="dt">Maybe</span> (addr, a))</a>
<a class="sourceLine" id="cb7-8" data-line-number="8"> <span class="co">-- ^ (write address @w@, value to write)</span></a>
<a class="sourceLine" id="cb7-9" data-line-number="9"> <span class="ot">-&gt;</span> <span class="dt">Signal</span> dom a</a>
<a class="sourceLine" id="cb7-10" data-line-number="10"> <span class="co">-- ^ The @blockRAM@ at address @r@ from the previous cycle</span></a></code></pre></div>
<aside class="notes">
<p>one more primitive to cover</p>
</aside>
</section></section>
<section><section id="brainfuck-cpu" class="title-slide slide level2"><h2>BrainFuck cpu</h2></section><section class="slide level3">
<ul>
<li>Implement as a simple state machine</li>
</ul>
</section><section class="slide level3">
<div class="sourceCode" id="cb8"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb8-1" data-line-number="1"><span class="kw">data</span> <span class="dt">Instruction</span></a>
<a class="sourceLine" id="cb8-2" data-line-number="2"> <span class="fu">=</span> <span class="dt">IncPtr</span></a>
<a class="sourceLine" id="cb8-3" data-line-number="3"> <span class="fu">|</span> <span class="dt">DecPtr</span></a>
<a class="sourceLine" id="cb8-4" data-line-number="4"> <span class="fu">|</span> <span class="dt">Inc</span></a>
<a class="sourceLine" id="cb8-5" data-line-number="5"> <span class="fu">|</span> <span class="dt">Dec</span></a>
<a class="sourceLine" id="cb8-6" data-line-number="6"> <span class="fu">|</span> <span class="dt">Output</span></a>
<a class="sourceLine" id="cb8-7" data-line-number="7"> <span class="fu">|</span> <span class="dt">Input</span></a>
<a class="sourceLine" id="cb8-8" data-line-number="8"> <span class="fu">|</span> <span class="dt">Open</span></a>
<a class="sourceLine" id="cb8-9" data-line-number="9"> <span class="fu">|</span> <span class="dt">Close</span></a></code></pre></div>
<aside class="notes">
<p>Instructions are a regular ADT</p>
<p>Clash compiles these to an 8 bit representation</p>
<p>(may not be optimal)</p>
</aside>
</section><section class="slide level3">
<div class="sourceCode" id="cb9"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb9-1" data-line-number="1"><span class="kw">type</span> <span class="dt">MaxNesting</span> <span class="fu">=</span> <span class="dv">256</span></a>
<a class="sourceLine" id="cb9-2" data-line-number="2"><span class="kw">type</span> <span class="dt">WordSize</span> <span class="fu">=</span> <span class="dv">8</span></a>
<a class="sourceLine" id="cb9-3" data-line-number="3"><span class="kw">type</span> <span class="dt">Word</span> <span class="fu">=</span> <span class="dt">Unsigned</span> <span class="dt">WordSize</span></a>
<a class="sourceLine" id="cb9-4" data-line-number="4"><span class="kw">type</span> <span class="dt">DataAddrSize</span> <span class="fu">=</span> <span class="dv">10</span></a>
<a class="sourceLine" id="cb9-5" data-line-number="5"><span class="kw">type</span> <span class="dt">DataAddr</span> <span class="fu">=</span> <span class="dt">Unsigned</span> <span class="dt">DataAddrSize</span></a>
<a class="sourceLine" id="cb9-6" data-line-number="6"><span class="kw">type</span> <span class="dt">InstAddrSize</span> <span class="fu">=</span> <span class="dv">11</span></a>
<a class="sourceLine" id="cb9-7" data-line-number="7"><span class="kw">type</span> <span class="dt">InstAddr</span> <span class="fu">=</span> <span class="dt">Unsigned</span> <span class="dt">InstAddrSize</span></a>
<a class="sourceLine" id="cb9-8" data-line-number="8"></a>
<a class="sourceLine" id="cb9-9" data-line-number="9"><span class="kw">data</span> <span class="dt">Pop</span> <span class="fu">=</span> <span class="dt">DoNotPop</span> <span class="fu">|</span> <span class="dt">Pop</span></a>
<a class="sourceLine" id="cb9-10" data-line-number="10"> <span class="kw">deriving</span> (<span class="dt">Show</span>)</a></code></pre></div>
<aside class="notes">
<p>Some types we’ll be using</p>
</aside>
</section><section class="slide level3">
<div class="sourceCode" id="cb10"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb10-1" data-line-number="1">cpu</a>
<a class="sourceLine" id="cb10-2" data-line-number="2"><span class="ot"> ::</span> <span class="dt">Signal</span> d <span class="dt">Word</span></a>
<a class="sourceLine" id="cb10-3" data-line-number="3"> <span class="ot">-&gt;</span> <span class="dt">Signal</span> d (<span class="dt">Maybe</span> <span class="dt">Word</span>, <span class="dt">Pop</span>)</a></code></pre></div>
<aside class="notes">
<p>inputs are moved on whenever we pop</p>
</aside>
</section><section class="slide level3">
<div class="sourceCode" id="cb11"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb11-1" data-line-number="1"><span class="kw">data</span> <span class="dt">State</span></a>
<a class="sourceLine" id="cb11-2" data-line-number="2"> <span class="fu">=</span> <span class="dt">Running</span> <span class="dt">DataAddr</span> <span class="dt">InstAddr</span></a>
<a class="sourceLine" id="cb11-3" data-line-number="3"> <span class="fu">|</span> <span class="dt">FindMatching</span> <span class="dt">DataAddr</span> <span class="dt">InstAddr</span> <span class="dt">Direction</span> (<span class="dt">Index</span> <span class="dt">MaxNesting</span>)</a>
<a class="sourceLine" id="cb11-4" data-line-number="4"></a>
<a class="sourceLine" id="cb11-5" data-line-number="5"><span class="kw">data</span> <span class="dt">Direction</span> <span class="fu">=</span> <span class="dt">Forwards</span> <span class="fu">|</span> <span class="dt">Backwards</span></a></code></pre></div>
</section><section class="slide level3">
<div class="sourceCode" id="cb12"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb12-1" data-line-number="1">advanceState</a>
<a class="sourceLine" id="cb12-2" data-line-number="2"><span class="ot"> ::</span> <span class="dt">Word</span></a>
<a class="sourceLine" id="cb12-3" data-line-number="3"> <span class="co">-- ^ The data at the previously requested address</span></a>
<a class="sourceLine" id="cb12-4" data-line-number="4"> <span class="ot">-&gt;</span> <span class="dt">Instruction</span></a>
<a class="sourceLine" id="cb12-5" data-line-number="5"> <span class="co">-- ^ The instruction at the previously requested address</span></a>
<a class="sourceLine" id="cb12-6" data-line-number="6"> <span class="ot">-&gt;</span> <span class="dt">Word</span></a>
<a class="sourceLine" id="cb12-7" data-line-number="7"> <span class="co">-- ^ The input data</span></a>
<a class="sourceLine" id="cb12-8" data-line-number="8"> <span class="ot">-&gt;</span> <span class="dt">State</span></a>
<a class="sourceLine" id="cb12-9" data-line-number="9"> <span class="co">-- ^ The previous state</span></a>
<a class="sourceLine" id="cb12-10" data-line-number="10"> <span class="ot">-&gt;</span> (<span class="dt">Maybe</span> <span class="dt">DataOp</span>, <span class="dt">Maybe</span> <span class="dt">Word</span>, <span class="dt">Pop</span>, <span class="dt">State</span>)</a>
<a class="sourceLine" id="cb12-11" data-line-number="11"> <span class="co">-- ^ (The op to perform on the current cell, output value, did we consume input, the next state)</span></a></code></pre></div>
<aside class="notes">
<p>the definition is pretty pedestrian</p>
</aside>
</section><section class="slide level3">
<div class="sourceCode" id="cb13"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb13-1" data-line-number="1">cpu input</a>
<a class="sourceLine" id="cb13-2" data-line-number="2"> <span class="fu">=</span> <span class="kw">let</span></a>
<a class="sourceLine" id="cb13-3" data-line-number="3"> (dataOp, output, pop, state) <span class="fu">=</span></a>
<a class="sourceLine" id="cb13-4" data-line-number="4"> unbundle</a>
<a class="sourceLine" id="cb13-5" data-line-number="5"> <span class="fu">$</span> advanceState</a>
<a class="sourceLine" id="cb13-6" data-line-number="6"> <span class="fu">&lt;$&gt;</span> data_</a>
<a class="sourceLine" id="cb13-7" data-line-number="7"> <span class="fu">&lt;*&gt;</span> instruction</a>
<a class="sourceLine" id="cb13-8" data-line-number="8"> <span class="fu">&lt;*&gt;</span> input</a>
<a class="sourceLine" id="cb13-9" data-line-number="9"> <span class="fu">&lt;*&gt;</span> prevState</a>
<a class="sourceLine" id="cb13-10" data-line-number="10"><span class="fu">...</span></a></code></pre></div>
</section><section class="slide level3">
<div class="sourceCode" id="cb14"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb14-1" data-line-number="1"><span class="fu">...</span></a>
<a class="sourceLine" id="cb14-2" data-line-number="2"> dataAddr <span class="fu">=</span> stateDataAddr <span class="fu">&lt;$&gt;</span> state</a>
<a class="sourceLine" id="cb14-3" data-line-number="3"> instAddr <span class="fu">=</span> stateInstAddr <span class="fu">&lt;$&gt;</span> state</a>
<a class="sourceLine" id="cb14-4" data-line-number="4"> data_ <span class="fu">=</span> poker dataAddr dataOp</a>
<a class="sourceLine" id="cb14-5" data-line-number="5"></a>
<a class="sourceLine" id="cb14-6" data-line-number="6"> instruction <span class="fu">=</span> blockRam program instAddr (pure <span class="dt">Nothing</span>)</a>
<a class="sourceLine" id="cb14-7" data-line-number="7"></a>
<a class="sourceLine" id="cb14-8" data-line-number="8"> initialState <span class="fu">=</span> <span class="dt">Running</span> <span class="dv">0</span> <span class="dv">0</span></a>
<a class="sourceLine" id="cb14-9" data-line-number="9"> prevState <span class="fu">=</span> register initialState state</a>
<a class="sourceLine" id="cb14-10" data-line-number="10"> <span class="kw">in</span></a>
<a class="sourceLine" id="cb14-11" data-line-number="11"> bundle (output, pop)</a></code></pre></div>
</section><section class="slide level3">
<div class="sourceCode" id="cb15"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb15-1" data-line-number="1">poker</a>
<a class="sourceLine" id="cb15-2" data-line-number="2"><span class="ot"> ::</span> <span class="dt">Signal</span> d <span class="dt">DataAddr</span></a>
<a class="sourceLine" id="cb15-3" data-line-number="3"> <span class="co">-- ^ The address we would like the data for</span></a>
<a class="sourceLine" id="cb15-4" data-line-number="4"> <span class="ot">-&gt;</span> <span class="dt">Signal</span> d (<span class="dt">Maybe</span> <span class="dt">DataOp</span>)</a>
<a class="sourceLine" id="cb15-5" data-line-number="5"> <span class="co">-- ^ An operation to perform on the data</span></a>
<a class="sourceLine" id="cb15-6" data-line-number="6"> <span class="ot">-&gt;</span> <span class="dt">Signal</span> d <span class="dt">Word</span></a>
<a class="sourceLine" id="cb15-7" data-line-number="7"> <span class="co">-- ^ The requested data, delayed by one</span></a>
<a class="sourceLine" id="cb15-8" data-line-number="8"> <span class="co">-- cycle</span></a>
<a class="sourceLine" id="cb15-9" data-line-number="9">poker dataPtr op <span class="fu">=</span> <span class="kw">let</span> <span class="fu">...</span></a></code></pre></div>
<aside class="notes">
<p>This handles manipulating the memory</p>
<p>the most interesting bit</p>
</aside>
</section><section class="slide level3">
<div class="sourceCode" id="cb16"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb16-1" data-line-number="1">initialContents <span class="fu">=</span> replicate (<span class="dt">SNat</span> <span class="fu">@</span>(<span class="dv">2</span> <span class="fu">^</span> <span class="dt">DataAddrSize</span>)) <span class="dv">0</span></a>
<a class="sourceLine" id="cb16-2" data-line-number="2">ram <span class="fu">=</span> blockRam initialContents dataPtr write</a></code></pre></div>
<aside class="notes">
<p>write is defined later all a bit circular</p>
</aside>
</section><section class="slide level3">
<div class="sourceCode" id="cb17"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb17-1" data-line-number="1"><span class="ot">delayedOp ::</span> <span class="dt">Signal</span> d (<span class="dt">Maybe</span> <span class="dt">DataOp</span>)</a>
<a class="sourceLine" id="cb17-2" data-line-number="2">delayedOp <span class="fu">=</span> register <span class="dt">Nothing</span> op</a></code></pre></div>
<aside class="notes">
<p>just to avoid repetition</p>
<p>there is type system machinery to keep this delaying safe</p>
<p>Omitted for this talk for conciseness</p>
</aside>
</section><section class="slide level3">
<div class="sourceCode" id="cb18"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb18-1" data-line-number="1"><span class="ot">applyOp ::</span> <span class="dt">Maybe</span> <span class="dt">DataOp</span> <span class="ot">-&gt;</span> <span class="dt">Word</span> <span class="ot">-&gt;</span> <span class="dt">Word</span></a>
<a class="sourceLine" id="cb18-2" data-line-number="2">applyOp <span class="fu">=</span> \<span class="kw">case</span></a>
<a class="sourceLine" id="cb18-3" data-line-number="3"> <span class="dt">Just</span> (<span class="dt">Store</span> x) <span class="ot">-&gt;</span> const x</a>
<a class="sourceLine" id="cb18-4" data-line-number="4"> <span class="dt">Just</span> <span class="dt">Increment</span> <span class="ot">-&gt;</span> succ</a>
<a class="sourceLine" id="cb18-5" data-line-number="5"> <span class="dt">Just</span> <span class="dt">Decrement</span> <span class="ot">-&gt;</span> pred</a>
<a class="sourceLine" id="cb18-6" data-line-number="6"> <span class="dt">Nothing</span> <span class="ot">-&gt;</span> id</a></code></pre></div>
<aside class="notes">
<p>Clash handles returning a function here with no problem</p>
</aside>
</section><section class="slide level3">
<div class="sourceCode" id="cb19"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb19-1" data-line-number="1"><span class="ot">operatedData ::</span> <span class="dt">Signal</span> d (<span class="dt">DataAddr</span>, <span class="dt">Word</span>)</a>
<a class="sourceLine" id="cb19-2" data-line-number="2">operatedData <span class="fu">=</span> (fmap <span class="fu">.</span> applyOp) <span class="fu">&lt;$&gt;</span> delayedOp <span class="fu">&lt;*&gt;</span> readData</a></code></pre></div>
<aside class="notes">
<p>The data after the operation, along with its address</p>
</aside>
</section><section class="slide level3">
<div class="sourceCode" id="cb20"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb20-1" data-line-number="1"><span class="co">-- If we have performed an operation, write the result into the RAM</span></a>
<a class="sourceLine" id="cb20-2" data-line-number="2"><span class="ot">write ::</span> <span class="dt">Signal</span> d (<span class="dt">Maybe</span> (<span class="dt">DataAddr</span>, <span class="dt">Word</span>))</a>
<a class="sourceLine" id="cb20-3" data-line-number="3">write <span class="fu">=</span> liftA2 (<span class="fu">$&gt;</span>) delayedOp operatedData</a></code></pre></div>
<aside class="notes">
<p>Write to ram when the data has changed, just for power saving</p>
</aside>
</section><section class="slide level3">
<div class="sourceCode" id="cb21"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb21-1" data-line-number="1"><span class="co">-- The value we wrote to RAM on the previous cycle</span></a>
<a class="sourceLine" id="cb21-2" data-line-number="2"><span class="ot">writeBack ::</span> <span class="dt">Signal</span> d (<span class="dt">Maybe</span> (<span class="dt">DataAddr</span>, <span class="dt">Word</span>))</a>
<a class="sourceLine" id="cb21-3" data-line-number="3">writeBack <span class="fu">=</span> register <span class="dt">Nothing</span> write</a></code></pre></div>
</section><section class="slide level3">
<div class="sourceCode" id="cb22"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb22-1" data-line-number="1"><span class="co">-- If we have written back to the same address, use that value, otherwise</span></a>
<a class="sourceLine" id="cb22-2" data-line-number="2"><span class="co">-- use the one we read last cycle</span></a>
<a class="sourceLine" id="cb22-3" data-line-number="3"><span class="ot">readData ::</span> <span class="dt">Signal</span> d (<span class="dt">DataAddr</span>, <span class="dt">Word</span>)</a>
<a class="sourceLine" id="cb22-4" data-line-number="4">readData <span class="fu">=</span> liftA3</a>
<a class="sourceLine" id="cb22-5" data-line-number="5"> (\read readAddr written <span class="ot">-&gt;</span> <span class="kw">case</span> written <span class="kw">of</span></a>
<a class="sourceLine" id="cb22-6" data-line-number="6"> <span class="dt">Just</span> (writtenAddr, d) <span class="fu">|</span> writtenAddr <span class="fu">==</span> readAddr <span class="ot">-&gt;</span> (writtenAddr, d)</a>
<a class="sourceLine" id="cb22-7" data-line-number="7"> _ <span class="ot">-&gt;</span> (readAddr, read)</a>
<a class="sourceLine" id="cb22-8" data-line-number="8"> )</a>
<a class="sourceLine" id="cb22-9" data-line-number="9"> ram</a>
<a class="sourceLine" id="cb22-10" data-line-number="10"> (register undefined <span class="fu">$</span> dataPtr)</a>
<a class="sourceLine" id="cb22-11" data-line-number="11"> writeBack</a></code></pre></div>
</section><section class="slide level3">
<div class="sourceCode" id="cb23"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb23-1" data-line-number="1">poker dataPtr op</a>
<a class="sourceLine" id="cb23-2" data-line-number="2"> <span class="fu">=</span> <span class="kw">let</span></a>
<a class="sourceLine" id="cb23-3" data-line-number="3"> <span class="co">-- If we have performed an operation, write the result into the RAM</span></a>
<a class="sourceLine" id="cb23-4" data-line-number="4"><span class="ot"> write ::</span> <span class="dt">Signal</span> d (<span class="dt">Maybe</span> (<span class="dt">DataAddr</span>, <span class="dt">Word</span>))</a>
<a class="sourceLine" id="cb23-5" data-line-number="5"> write <span class="fu">=</span> liftA2 (<span class="fu">$&gt;</span>) delayedOp operatedData</a>
<a class="sourceLine" id="cb23-6" data-line-number="6"></a>
<a class="sourceLine" id="cb23-7" data-line-number="7"> <span class="co">-- The value we wrote to RAM on the previous cycle</span></a>
<a class="sourceLine" id="cb23-8" data-line-number="8"><span class="ot"> writeBack ::</span> <span class="dt">Signal</span> d (<span class="dt">Maybe</span> (<span class="dt">DataAddr</span>, <span class="dt">Word</span>))</a>
<a class="sourceLine" id="cb23-9" data-line-number="9"> writeBack <span class="fu">=</span> register <span class="dt">Nothing</span> write</a>
<a class="sourceLine" id="cb23-10" data-line-number="10"></a>
<a class="sourceLine" id="cb23-11" data-line-number="11"> initialContents <span class="fu">=</span> replicate (<span class="dt">SNat</span> <span class="fu">@</span>(<span class="dv">2</span> <span class="fu">^</span> <span class="dt">DataAddrSize</span>)) <span class="dv">0</span></a>
<a class="sourceLine" id="cb23-12" data-line-number="12"><span class="ot"> ram ::</span> <span class="dt">Signal</span> d <span class="dt">Word</span></a>
<a class="sourceLine" id="cb23-13" data-line-number="13"> ram <span class="fu">=</span> blockRam initialContents dataPtr write</a>
<a class="sourceLine" id="cb23-14" data-line-number="14"></a>
<a class="sourceLine" id="cb23-15" data-line-number="15"> <span class="co">-- If we have written back to the same address, use that value, otherwise</span></a>
<a class="sourceLine" id="cb23-16" data-line-number="16"> <span class="co">-- use the one we read last cycle</span></a>
<a class="sourceLine" id="cb23-17" data-line-number="17"> <span class="co">-- Delayed by 1</span></a>
<a class="sourceLine" id="cb23-18" data-line-number="18"><span class="ot"> readData ::</span> <span class="dt">Signal</span> d (<span class="dt">DataAddr</span>, <span class="dt">Word</span>)</a>
<a class="sourceLine" id="cb23-19" data-line-number="19"> readData <span class="fu">=</span> liftA3</a>
<a class="sourceLine" id="cb23-20" data-line-number="20"> (\read readAddr written <span class="ot">-&gt;</span> <span class="kw">case</span> written <span class="kw">of</span></a>
<a class="sourceLine" id="cb23-21" data-line-number="21"> <span class="dt">Just</span> (writtenAddr, d) <span class="fu">|</span> writtenAddr <span class="fu">==</span> readAddr <span class="ot">-&gt;</span> (writtenAddr, d)</a>
<a class="sourceLine" id="cb23-22" data-line-number="22"> _ <span class="ot">-&gt;</span> (readAddr, read)</a>
<a class="sourceLine" id="cb23-23" data-line-number="23"> )</a>
<a class="sourceLine" id="cb23-24" data-line-number="24"> ram</a>
<a class="sourceLine" id="cb23-25" data-line-number="25"> (register undefined <span class="fu">$</span> dataPtr)</a>
<a class="sourceLine" id="cb23-26" data-line-number="26"> writeBack</a>
<a class="sourceLine" id="cb23-27" data-line-number="27"></a>
<a class="sourceLine" id="cb23-28" data-line-number="28"><span class="ot"> delayedOp ::</span> <span class="dt">Signal</span> d (<span class="dt">Maybe</span> <span class="dt">DataOp</span>)</a>
<a class="sourceLine" id="cb23-29" data-line-number="29"> delayedOp <span class="fu">=</span> register <span class="dt">Nothing</span> op</a>
<a class="sourceLine" id="cb23-30" data-line-number="30"></a>
<a class="sourceLine" id="cb23-31" data-line-number="31"> <span class="co">-- The data with the given operation applied to it</span></a>
<a class="sourceLine" id="cb23-32" data-line-number="32"> <span class="co">-- Delayed by 1</span></a>
<a class="sourceLine" id="cb23-33" data-line-number="33"><span class="ot"> operatedData ::</span> <span class="dt">Signal</span> d (<span class="dt">DataAddr</span>, <span class="dt">Word</span>)</a>
<a class="sourceLine" id="cb23-34" data-line-number="34"> operatedData <span class="fu">=</span> (fmap <span class="fu">.</span> applyOp) <span class="fu">&lt;$&gt;</span> delayedOp <span class="fu">&lt;*&gt;</span> readData</a>
<a class="sourceLine" id="cb23-35" data-line-number="35"></a>
<a class="sourceLine" id="cb23-36" data-line-number="36"> <span class="co">-- How to apply a BF instruction to some data</span></a>
<a class="sourceLine" id="cb23-37" data-line-number="37"><span class="ot"> applyOp ::</span> <span class="dt">Maybe</span> <span class="dt">DataOp</span> <span class="ot">-&gt;</span> <span class="dt">Word</span> <span class="ot">-&gt;</span> <span class="dt">Word</span></a>
<a class="sourceLine" id="cb23-38" data-line-number="38"> applyOp <span class="fu">=</span> \<span class="kw">case</span></a>
<a class="sourceLine" id="cb23-39" data-line-number="39"> <span class="dt">Just</span> (<span class="dt">Store</span> x) <span class="ot">-&gt;</span> const x</a>
<a class="sourceLine" id="cb23-40" data-line-number="40"> <span class="dt">Just</span> <span class="dt">Increment</span> <span class="ot">-&gt;</span> succ</a>
<a class="sourceLine" id="cb23-41" data-line-number="41"> <span class="dt">Just</span> <span class="dt">Decrement</span> <span class="ot">-&gt;</span> pred</a>
<a class="sourceLine" id="cb23-42" data-line-number="42"> <span class="dt">Nothing</span> <span class="ot">-&gt;</span> id</a>
<a class="sourceLine" id="cb23-43" data-line-number="43"> <span class="kw">in</span></a>
<a class="sourceLine" id="cb23-44" data-line-number="44"> replaceFirst <span class="dv">0</span> (snd <span class="fu">&lt;$&gt;</span> operatedData)</a></code></pre></div>
</section><section class="slide level3">
<p>!</p>
<aside class="notes">
<p>That’s it, the CPU is defined</p>
</aside>
</section><section class="slide level3">
<div class="sourceCode" id="cb24"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb24-1" data-line-number="1"><span class="ot">program ::</span> <span class="dt">Vec</span> (<span class="dv">2</span> <span class="fu">^</span> <span class="dt">InstAddrSize</span>) <span class="dt">Instruction</span></a>
<a class="sourceLine" id="cb24-2" data-line-number="2">program <span class="fu">=</span> <span class="fu">$</span>(listToVecTH (parseBF</a>
<a class="sourceLine" id="cb24-3" data-line-number="3"> <span class="st">&quot;.++++++++[&gt;++++[&gt;++&gt;+++&gt;+++&gt;+&lt;&lt;&lt;&lt;-]&gt;+&gt;+&gt;-&gt;&gt;+[&lt;]&lt;-]&gt;&gt;.&gt;---.+++++++..+++.&gt;&gt;.&lt;-.&lt;.+++.------.--------.&gt;&gt;+.&gt;++.&quot;</span></a>
<a class="sourceLine" id="cb24-4" data-line-number="4"> )) <span class="fu">++</span> loop <span class="fu">++</span> repeat <span class="dt">Inc</span></a>
<a class="sourceLine" id="cb24-5" data-line-number="5"></a>
<a class="sourceLine" id="cb24-6" data-line-number="6">loop <span class="fu">=</span> <span class="fu">$</span>(listToVecTH (parseBF <span class="st">&quot;[]+[]&quot;</span>))</a></code></pre></div>
</section><section class="slide level3">
<p>Testing is very easy with Clash</p>
<div class="sourceCode" id="cb25"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb25-1" data-line-number="1">sample_lazy <span class="fu">$</span> cpu (pure <span class="dv">0</span>)</a></code></pre></div>
<div class="fragment">
<div class="sourceCode" id="cb26"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb26-1" data-line-number="1">fmap (chr <span class="fu">.</span> fromIntegral) <span class="fu">.</span> catMaybes <span class="fu">.</span> fmap fst <span class="fu">$</span> go</a>
<a class="sourceLine" id="cb26-2" data-line-number="2"><span class="st">&quot;Hello World!\n</span></a></code></pre></div>
</div>
</section><section id="improvement" class="slide level3">
<h3>Improvement</h3>
<ul>
<li>Keeping track of matching parentheses</li>
<li>Consuming multiple instructions per cycle</li>
</ul>
</section><section class="slide level3">
<pre><code>-[---&gt;+&lt;]&gt;-.[----&gt;+++++&lt;]
&gt;-.-------.+++++++++++++.
&gt;---.++++++++.+[----&gt;+&lt;]&gt;
&gt;+++.++[-&gt;+++&lt;]&gt;.++++++++
&gt;+.+++.[--&gt;+++++&lt;]&gt;+++.++
&gt;[---&gt;++&lt;]&gt;.---.+++++++++
&gt;+.+.+++[-&gt;+++&lt;]&gt;.+++++++
&gt;++.-----.+++++.-------.-</code></pre>
</section><section class="slide level3">
<!--
```haskell
fib :: Signal domain Word32
fib =
let delayed1 = register 0 fib
delayed2 = register 0 (register 1 fib)
in (+) <$> delayed1 <*> delayed2
```
::: notes
:::
-->
</section></section>
</div>
</div>
<script src="http://cdn.rawgit.com/hakimel/reveal.js/3.5.0//lib/js/head.min.js"></script>
<script src="http://cdn.rawgit.com/hakimel/reveal.js/3.5.0//js/reveal.js"></script>
<script>
// Full list of configuration options available at:
// https://github.com/hakimel/reveal.js#configuration
Reveal.initialize({
// Push each slide change to the browser history
history: true,
// Optional reveal.js plugins
dependencies: [
{ src: 'http://cdn.rawgit.com/hakimel/reveal.js/3.5.0//lib/js/classList.js', condition: function() { return !document.body.classList; } },
{ src: 'http://cdn.rawgit.com/hakimel/reveal.js/3.5.0//plugin/zoom-js/zoom.js', async: true },
{ src: 'http://cdn.rawgit.com/hakimel/reveal.js/3.5.0//plugin/notes/notes.js', async: true }
]
});
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment