<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://aaryanvdhawan.github.io/feed.xml" rel="self" type="application/atom+xml" /><link href="https://aaryanvdhawan.github.io/" rel="alternate" type="text/html" /><updated>2025-09-16T00:54:15+00:00</updated><id>https://aaryanvdhawan.github.io/feed.xml</id><title type="html">Aaryan Dhawan | Computer Engineer</title><subtitle>personal description</subtitle><author><name>Aaryan Dhawan</name><email>aaryanvaldhawan@gmail.com</email></author><entry><title type="html">Optimizing an STDP Learning Engine for FPGAs</title><link href="https://aaryanvdhawan.github.io/posts/2025/07/optimizing-an-stdp-learning-engine-for-fpgas/" rel="alternate" type="text/html" title="Optimizing an STDP Learning Engine for FPGAs" /><published>2025-07-01T00:00:00+00:00</published><updated>2025-07-01T00:00:00+00:00</updated><id>https://aaryanvdhawan.github.io/posts/2025/07/blog-post-1</id><content type="html" xml:base="https://aaryanvdhawan.github.io/posts/2025/07/optimizing-an-stdp-learning-engine-for-fpgas/"><![CDATA[<p>Written by Aaryan Dhawan, in collaboration with <a href="https://github.com/muhammadfarhan720">Muhammad Farhan Azmine</a></p>

<h1 id="what-is-stdp">What is STDP?</h1>

<p>Spike-Timing-Dependent Plasticity (STDP) is a biological learning rule that adjusts the strength of connections between neurons based on the relative timing of their spikes. In simple terms within a pair of neurons, if the presynaptic neuron fires before the post synaptic neuron, the connection between them is strengthened. Conversely if the presynaptic neuron fires later than the post synaptic neuron, the connection is weakened. In machine learning, STDP is used to train some Spiking Neural Networks (SNNs) by mimicking this biological process, allowing the network to learn from temporal patterns in data. 
Using temporal patterns to learn, STDP allows SNNs to process information similarly to the human brain, making them suitable for tasks like real-time learning, robotics, and in edge computing.</p>

<h2 id="on-chip-stdp-learning">On-Chip STDP Learning</h2>

<p>On-chip STDP learning refers to the implementation of the STDP learning algorithm directly within machine learning hardware accelerators, rather than training the network in software and transferring it to hardware. This approach is particularly beneficial for applications with limited data availability or when power consumption is a concern. In 2019, researches at Texas A&amp;M University developed FPGA efficient, STDP based SNN models for both supervised and unsupervised learning <a href="https://dl.acm.org/doi/10.1145/3313866">1</a> with Liquid State machines (LSMs). In this work, they build a STDP learning engine that takes the spike timing difference between the current neuron output and the presynaptic neuron, and uses that to determine between strengthening (Potentiation) or weakening (Depression) the connection between the two neurons. This adjustment value is determined by the following equations:</p>
<h2 id="equation-stdp-potentiation-depression">STDP Potentiation and Depression Equations</h2>
<p>\(\Delta w = \begin{cases}
\eta_{+} \cdot e^{-\frac{t_{pre}-t_{post}}{\tau_{+}}} &amp; \text{if } t_{pre} &lt; t_{post} \\
-\eta_{-} \cdot e^{-\frac{t_{post}-t_{pre}}{\tau_{-}}} &amp; \text{if } t_{pre} &gt; t_{post} 
\end{cases}\)</p>

<p>where:</p>
<ul>
  <li>\(\Delta w\) is the change in weight</li>
  <li>\(t_{pre}\) is the time of the pre-synaptic spike</li>
  <li>\(t_{post}\) is the time of the post-synaptic/current neuron spike</li>
  <li>\(\tau_{+}\) is the time constant for potentiation</li>
  <li>\(\tau_{-}\) is the time constant for depression</li>
  <li>\(\eta_{+}\) is the amplitude of the potentiation curve</li>
  <li>\(\eta_{-}\) is the amplitude of the depression curve</li>
</ul>

<p>Over a given sample period, each neuron will produce a spike train, which is compared against the spike generated from the presynaptic neurons to compute a timing difference values, \(\Delta t\). This \(\Delta t\) is used to calculate the potentiation or depression value, strengthening or weakening a given connection. Determining potentiation vs depression can be visualized as follows:
<img src="/images/STDP_learning.gif" alt="STDP Simulation" />
If the presynaptic neuron spikes before the post-synaptic neuron, the timing difference \(\Delta t\) is positive, indicating that the connection should be strengthened (potentiation). Conversely, if the presynaptic neuron spikes after the post-synaptic neuron, the timing difference \(\Delta t\) is negative, indicating that the connection should be weakened (depression).</p>

<h2 id="original-hardware-design">Original Hardware Design</h2>

<p>In <a href="https://dl.acm.org/doi/10.1145/3313866">1</a>, the authors develop a “hardware-friendly STDP learning engine”, recreated in the simplified diagram below. 
<img src="/images/SotA_STDP_LE_diagram.png" alt="STDP Learning Engine" />
Although the referred diagram from <a href="https://dl.acm.org/doi/10.1145/3313866">1</a> shows a simplified architecture, the actual datapath should be as the following, including the registers within the datapath to avoid metastability issues: 
<img src="/images/SotA_STDP_LE_PL.png" alt="STDP Learning Engine with Register" />
Discrete spike trains from the presynaptic neurons and post-synaptic/current neuron outputs are fed into Serial-In/Parallel-Out (SIPO) shift registers, the “length” of the registers are equal to the length of the timing window memory between the post synaptic spike and the presynaptic spikes. The shift registers corresponding to the presynaptic neurons are then selected by an M to 1 multiplexer, where M is the number of presynaptic neurons connected to the current post synaptic neuron, which possessing the learning engine. Once one of the presynaptic shift registers is selected and its data is passed through the multiplexer, the contents of the selected presynaptic and the post synaptic shift registers are compared to each other to determine the \(\Delta t\) to adjust that given weight. This is done by comparator, which looks at the Most Significant bit(MSB) of the two spike trains and looks at which of the two is high/Logic-1. If the Pre-synaptic shift register MSB is high, the content of the post-synaptic shift register will be sent to the priority encoder and the produced output \(\Delta t\) will be a negative timing difference. Vice versa, if the Post-synaptic shift register MSB is high, the content of the pre-synaptic shift register will be sent to the priority encoder and the produced output \(\Delta t\) will be a positive timing difference. We can model this design in the following verilog code:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">always_ff</span> <span class="o">@</span><span class="p">(</span><span class="kt">posedge</span> <span class="n">clk</span><span class="p">)</span> <span class="k">begin</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">rst</span><span class="p">)</span> <span class="k">begin</span>
            <span class="n">data_reg</span> <span class="o">&lt;=</span> <span class="mb">16'b0</span><span class="p">;</span>
            <span class="n">flag</span> <span class="o">&lt;=</span> <span class="mb">1'b0</span><span class="p">;</span>
            <span class="n">LUT_out_reg</span> <span class="o">&lt;=</span> <span class="mb">20'b0</span><span class="p">;</span>
        <span class="k">end</span> <span class="k">else</span> <span class="k">begin</span>
            <span class="k">if</span><span class="p">(</span><span class="n">Post</span><span class="p">[</span><span class="mi">15</span><span class="p">]</span><span class="o">==</span><span class="mi">1</span><span class="p">)</span> <span class="k">begin</span>
                <span class="n">data_reg</span> <span class="o">&lt;=</span> <span class="n">Pre</span><span class="p">;</span>
                <span class="n">flag</span> <span class="o">&lt;=</span> <span class="mb">1'b0</span><span class="p">;</span> <span class="c1">// Post-synaptic neuron is active, set flag to 0</span>
            <span class="k">end</span>
            <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">Pre</span><span class="p">[</span><span class="mi">15</span><span class="p">]</span> <span class="o">==</span> <span class="mi">1</span><span class="p">)</span> <span class="k">begin</span>
                <span class="n">data_reg</span> <span class="o">&lt;=</span> <span class="n">Post</span><span class="p">;</span>
                <span class="n">flag</span> <span class="o">&lt;=</span> <span class="mb">1'b1</span><span class="p">;</span> <span class="c1">// Pre-synaptic neuron is active, set flag to 1</span>
            <span class="k">end</span>
            <span class="k">else</span> <span class="k">begin</span>
                <span class="n">data_reg</span> <span class="o">&lt;=</span> <span class="mb">16'b0</span><span class="p">;</span> <span class="c1">// No active neuron, reset to zero</span>
                <span class="n">flag</span> <span class="o">&lt;=</span> <span class="mb">1'b0</span><span class="p">;</span> <span class="c1">// Reset flag</span>
            <span class="k">end</span>
            <span class="c1">// Update LUT output register</span>
            <span class="n">LUT_out_reg</span> <span class="o">&lt;=</span> <span class="n">LUT_out</span><span class="p">;</span> <span class="c1">// Store LUT output in register</span>
        <span class="k">end</span>
    <span class="k">end</span>

    <span class="k">always_comb</span> <span class="k">begin</span>
        <span class="k">if</span><span class="p">(</span><span class="n">flag</span><span class="p">)</span> <span class="k">begin</span>
            <span class="k">unique</span> <span class="k">casez</span><span class="p">(</span><span class="n">data_reg</span><span class="p">)</span>
                <span class="mb">16'b1???????????????</span><span class="o">:</span> <span class="n">TimingDifference</span> <span class="o">=</span> <span class="mi">6</span><span class="err">'</span><span class="n">sd0</span><span class="p">;</span> <span class="c1">// 0</span>
                <span class="mb">16'b01??????????????</span><span class="o">:</span> <span class="n">TimingDifference</span> <span class="o">=</span> <span class="mi">6</span><span class="err">'</span><span class="n">sd1</span><span class="p">;</span> <span class="c1">// 1</span>
                <span class="mb">16'b001?????????????</span><span class="o">:</span> <span class="n">TimingDifference</span> <span class="o">=</span> <span class="mi">6</span><span class="err">'</span><span class="n">sd2</span><span class="p">;</span> <span class="c1">// 2</span>
                <span class="mb">16'b0001????????????</span><span class="o">:</span> <span class="n">TimingDifference</span> <span class="o">=</span> <span class="mi">6</span><span class="err">'</span><span class="n">sd3</span><span class="p">;</span> <span class="c1">// 3</span>
                <span class="mb">16'b00001???????????</span><span class="o">:</span> <span class="n">TimingDifference</span> <span class="o">=</span> <span class="mi">6</span><span class="err">'</span><span class="n">sd4</span><span class="p">;</span> <span class="c1">// 4</span>
                <span class="mb">16'b000001??????????</span><span class="o">:</span> <span class="n">TimingDifference</span> <span class="o">=</span> <span class="mi">6</span><span class="err">'</span><span class="n">sd5</span><span class="p">;</span> <span class="c1">// 5</span>
                <span class="mb">16'b0000001?????????</span><span class="o">:</span> <span class="n">TimingDifference</span> <span class="o">=</span> <span class="mi">6</span><span class="err">'</span><span class="n">sd6</span><span class="p">;</span> <span class="c1">// 6</span>
                <span class="mb">16'b00000001????????</span><span class="o">:</span> <span class="n">TimingDifference</span> <span class="o">=</span> <span class="mi">6</span><span class="err">'</span><span class="n">sd7</span><span class="p">;</span> <span class="c1">// 7</span>
                <span class="mb">16'b000000001???????</span><span class="o">:</span> <span class="n">TimingDifference</span> <span class="o">=</span> <span class="mi">6</span><span class="err">'</span><span class="n">sd8</span><span class="p">;</span> <span class="c1">// 8</span>
                <span class="mb">16'b0000000001??????</span><span class="o">:</span> <span class="n">TimingDifference</span> <span class="o">=</span> <span class="mi">6</span><span class="err">'</span><span class="n">sd9</span><span class="p">;</span> <span class="c1">// 9</span>
                <span class="mb">16'b00000000001?????</span><span class="o">:</span> <span class="n">TimingDifference</span> <span class="o">=</span> <span class="mi">6</span><span class="err">'</span><span class="n">sd10</span><span class="p">;</span> <span class="c1">// 10</span>
                <span class="mb">16'b000000000001????</span><span class="o">:</span> <span class="n">TimingDifference</span> <span class="o">=</span> <span class="mi">6</span><span class="err">'</span><span class="n">sd11</span><span class="p">;</span> <span class="c1">// 11</span>
                <span class="mb">16'b0000000000001???</span><span class="o">:</span> <span class="n">TimingDifference</span> <span class="o">=</span> <span class="mi">6</span><span class="err">'</span><span class="n">sd12</span><span class="p">;</span> <span class="c1">// 12</span>
                <span class="mb">16'b00000000000001??</span><span class="o">:</span> <span class="n">TimingDifference</span> <span class="o">=</span> <span class="mi">6</span><span class="err">'</span><span class="n">sd13</span><span class="p">;</span> <span class="c1">// 13</span>
                <span class="mb">16'b000000000000001?</span><span class="o">:</span> <span class="n">TimingDifference</span> <span class="o">=</span> <span class="mi">6</span><span class="err">'</span><span class="n">sd14</span><span class="p">;</span> <span class="c1">// 14</span>
                <span class="mb">16'b0000000000000001</span><span class="o">:</span> <span class="n">TimingDifference</span> <span class="o">=</span> <span class="mi">6</span><span class="err">'</span><span class="n">sd15</span><span class="p">;</span> <span class="c1">// 15</span>
                <span class="nl">default:</span>              <span class="n">TimingDifference</span> <span class="o">=</span> <span class="mi">6</span><span class="err">'</span><span class="n">sd0</span><span class="p">;</span> <span class="c1">// Default case</span>
            <span class="k">endcase</span>
        <span class="k">end</span>
        <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">flag</span><span class="p">)</span> <span class="k">begin</span>
            <span class="k">unique</span> <span class="k">casez</span><span class="p">(</span><span class="n">data_reg</span><span class="p">)</span>
                    <span class="mb">16'b1???????????????</span><span class="o">:</span> <span class="n">TimingDifference</span> <span class="o">=</span> <span class="o">-</span><span class="mi">6</span><span class="err">'</span><span class="n">sd0</span><span class="p">;</span> <span class="c1">// 0</span>
                    <span class="mb">16'b01??????????????</span><span class="o">:</span> <span class="n">TimingDifference</span> <span class="o">=</span> <span class="o">-</span><span class="mi">6</span><span class="err">'</span><span class="n">sd1</span><span class="p">;</span> <span class="c1">// 1</span>
                    <span class="mb">16'b001?????????????</span><span class="o">:</span> <span class="n">TimingDifference</span> <span class="o">=</span> <span class="o">-</span><span class="mi">6</span><span class="err">'</span><span class="n">sd2</span><span class="p">;</span> <span class="c1">// 2</span>
                    <span class="mb">16'b0001????????????</span><span class="o">:</span> <span class="n">TimingDifference</span> <span class="o">=</span> <span class="o">-</span><span class="mi">6</span><span class="err">'</span><span class="n">sd3</span><span class="p">;</span> <span class="c1">// 3</span>
                    <span class="mb">16'b00001???????????</span><span class="o">:</span> <span class="n">TimingDifference</span> <span class="o">=</span> <span class="o">-</span><span class="mi">6</span><span class="err">'</span><span class="n">sd4</span><span class="p">;</span> <span class="c1">// 4</span>
                    <span class="mb">16'b000001??????????</span><span class="o">:</span> <span class="n">TimingDifference</span> <span class="o">=</span> <span class="o">-</span><span class="mi">6</span><span class="err">'</span><span class="n">sd5</span><span class="p">;</span> <span class="c1">// 5</span>
                    <span class="mb">16'b0000001?????????</span><span class="o">:</span> <span class="n">TimingDifference</span> <span class="o">=</span> <span class="o">-</span><span class="mi">6</span><span class="err">'</span><span class="n">sd6</span><span class="p">;</span> <span class="c1">// 6</span>
                    <span class="mb">16'b00000001????????</span><span class="o">:</span> <span class="n">TimingDifference</span> <span class="o">=</span> <span class="o">-</span><span class="mi">6</span><span class="err">'</span><span class="n">sd7</span><span class="p">;</span> <span class="c1">// 7</span>
                    <span class="mb">16'b000000001???????</span><span class="o">:</span> <span class="n">TimingDifference</span> <span class="o">=</span> <span class="o">-</span><span class="mi">6</span><span class="err">'</span><span class="n">sd8</span><span class="p">;</span> <span class="c1">// 8</span>
                    <span class="mb">16'b0000000001??????</span><span class="o">:</span> <span class="n">TimingDifference</span> <span class="o">=</span> <span class="o">-</span><span class="mi">6</span><span class="err">'</span><span class="n">sd9</span><span class="p">;</span> <span class="c1">// 9</span>
                    <span class="mb">16'b00000000001?????</span><span class="o">:</span> <span class="n">TimingDifference</span> <span class="o">=</span> <span class="o">-</span><span class="mi">6</span><span class="err">'</span><span class="n">sd10</span><span class="p">;</span> <span class="c1">// 10</span>
                    <span class="mb">16'b000000000001????</span><span class="o">:</span> <span class="n">TimingDifference</span> <span class="o">=</span> <span class="o">-</span><span class="mi">6</span><span class="err">'</span><span class="n">sd11</span><span class="p">;</span> <span class="c1">// 11</span>
                    <span class="mb">16'b0000000000001???</span><span class="o">:</span> <span class="n">TimingDifference</span> <span class="o">=</span> <span class="o">-</span><span class="mi">6</span><span class="err">'</span><span class="n">sd12</span><span class="p">;</span> <span class="c1">// 12</span>
                    <span class="mb">16'b00000000000001??</span><span class="o">:</span> <span class="n">TimingDifference</span> <span class="o">=</span> <span class="o">-</span><span class="mi">6</span><span class="err">'</span><span class="n">sd13</span><span class="p">;</span> <span class="c1">// 13</span>
                    <span class="mb">16'b000000000000001?</span><span class="o">:</span> <span class="n">TimingDifference</span> <span class="o">=</span> <span class="o">-</span><span class="mi">6</span><span class="err">'</span><span class="n">sd14</span><span class="p">;</span> <span class="c1">// 14</span>
                    <span class="mb">16'b0000000000000001</span><span class="o">:</span> <span class="n">TimingDifference</span> <span class="o">=</span> <span class="o">-</span><span class="mi">6</span><span class="err">'</span><span class="n">sd15</span><span class="p">;</span> <span class="c1">// 15</span>
                    <span class="nl">default:</span>              <span class="n">TimingDifference</span> <span class="o">=</span> <span class="o">-</span><span class="mi">6</span><span class="err">'</span><span class="n">sd0</span><span class="p">;</span> <span class="c1">// Default case</span>
                <span class="k">endcase</span>
        <span class="k">end</span>
</code></pre></div></div>
<p>Rather than implementing hardware to compute the potention/depression values with the <a href="#equation-stdp-potentiation-depression">2 equations above</a>, the authors use a single Look-Up Table (LUT), containing both positive and negative values to easily compute \(\Delta w\) as there is only a certain range of possible values. \(\Delta w\) is then added to synaptic connection, read from a memory block, using a simple adder. The synaptic connection is then written back to the memory block, completing the learning process for that given connection. The LUT and Adder are implemented as follows:</p>
<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="k">unique</span> <span class="k">casez</span><span class="p">(</span><span class="n">TimingDifference</span><span class="p">)</span>
            <span class="o">-</span><span class="err">'</span><span class="n">sd15</span><span class="o">:</span>  <span class="n">LUT_out</span> <span class="o">=</span> <span class="o">-</span><span class="err">'</span><span class="n">sd22</span><span class="p">;</span>
            <span class="o">-</span><span class="err">'</span><span class="n">sd14</span><span class="o">:</span>  <span class="n">LUT_out</span> <span class="o">=</span> <span class="o">-</span><span class="err">'</span><span class="n">sd25</span><span class="p">;</span>
            <span class="o">-</span><span class="err">'</span><span class="n">sd13</span><span class="o">:</span>  <span class="n">LUT_out</span> <span class="o">=</span> <span class="o">-</span><span class="err">'</span><span class="n">sd27</span><span class="p">;</span>
            <span class="o">-</span><span class="err">'</span><span class="n">sd12</span><span class="o">:</span>  <span class="n">LUT_out</span> <span class="o">=</span> <span class="o">-</span><span class="err">'</span><span class="n">sd30</span><span class="p">;</span>
            <span class="o">-</span><span class="err">'</span><span class="n">sd11</span><span class="o">:</span>  <span class="n">LUT_out</span> <span class="o">=</span> <span class="o">-</span><span class="err">'</span><span class="n">sd33</span><span class="p">;</span>
            <span class="o">-</span><span class="err">'</span><span class="n">sd10</span><span class="o">:</span>  <span class="n">LUT_out</span> <span class="o">=</span> <span class="o">-</span><span class="err">'</span><span class="n">sd37</span><span class="p">;</span>
            <span class="o">-</span><span class="err">'</span><span class="n">sd9</span><span class="o">:</span>   <span class="n">LUT_out</span> <span class="o">=</span> <span class="o">-</span><span class="err">'</span><span class="n">sd41</span><span class="p">;</span>
            <span class="o">-</span><span class="err">'</span><span class="n">sd8</span><span class="o">:</span>   <span class="n">LUT_out</span> <span class="o">=</span> <span class="o">-</span><span class="err">'</span><span class="n">sd45</span><span class="p">;</span>
            <span class="o">-</span><span class="err">'</span><span class="n">sd7</span><span class="o">:</span>   <span class="n">LUT_out</span> <span class="o">=</span> <span class="o">-</span><span class="err">'</span><span class="n">sd50</span><span class="p">;</span>
            <span class="o">-</span><span class="err">'</span><span class="n">sd6</span><span class="o">:</span>   <span class="n">LUT_out</span> <span class="o">=</span> <span class="o">-</span><span class="err">'</span><span class="n">sd55</span><span class="p">;</span>
            <span class="o">-</span><span class="err">'</span><span class="n">sd5</span><span class="o">:</span>   <span class="n">LUT_out</span> <span class="o">=</span> <span class="o">-</span><span class="err">'</span><span class="n">sd61</span><span class="p">;</span>
            <span class="o">-</span><span class="err">'</span><span class="n">sd4</span><span class="o">:</span>   <span class="n">LUT_out</span> <span class="o">=</span> <span class="o">-</span><span class="err">'</span><span class="n">sd67</span><span class="p">;</span>
            <span class="o">-</span><span class="err">'</span><span class="n">sd3</span><span class="o">:</span>   <span class="n">LUT_out</span> <span class="o">=</span> <span class="o">-</span><span class="err">'</span><span class="n">sd74</span><span class="p">;</span>
            <span class="o">-</span><span class="err">'</span><span class="n">sd2</span><span class="o">:</span>   <span class="n">LUT_out</span> <span class="o">=</span> <span class="o">-</span><span class="err">'</span><span class="n">sd82</span><span class="p">;</span>
            <span class="o">-</span><span class="err">'</span><span class="n">sd1</span><span class="o">:</span>   <span class="n">LUT_out</span> <span class="o">=</span> <span class="o">-</span><span class="err">'</span><span class="n">sd90</span><span class="p">;</span>
             <span class="err">'</span><span class="n">sd0</span><span class="o">:</span>   <span class="n">LUT_out</span> <span class="o">=</span>  <span class="err">'</span><span class="n">sd0</span><span class="p">;</span>
             <span class="err">'</span><span class="n">sd1</span><span class="o">:</span>   <span class="n">LUT_out</span> <span class="o">=</span>  <span class="err">'</span><span class="n">sd90</span><span class="p">;</span>
             <span class="err">'</span><span class="n">sd2</span><span class="o">:</span>   <span class="n">LUT_out</span> <span class="o">=</span>  <span class="err">'</span><span class="n">sd82</span><span class="p">;</span>
             <span class="err">'</span><span class="n">sd3</span><span class="o">:</span>   <span class="n">LUT_out</span> <span class="o">=</span>  <span class="err">'</span><span class="n">sd74</span><span class="p">;</span>
             <span class="err">'</span><span class="n">sd4</span><span class="o">:</span>   <span class="n">LUT_out</span> <span class="o">=</span>  <span class="err">'</span><span class="n">sd67</span><span class="p">;</span>
             <span class="err">'</span><span class="n">sd5</span><span class="o">:</span>   <span class="n">LUT_out</span> <span class="o">=</span>  <span class="err">'</span><span class="n">sd61</span><span class="p">;</span>
             <span class="err">'</span><span class="n">sd6</span><span class="o">:</span>   <span class="n">LUT_out</span> <span class="o">=</span>  <span class="err">'</span><span class="n">sd55</span><span class="p">;</span>
             <span class="err">'</span><span class="n">sd7</span><span class="o">:</span>   <span class="n">LUT_out</span> <span class="o">=</span>  <span class="err">'</span><span class="n">sd50</span><span class="p">;</span>    
             <span class="err">'</span><span class="n">sd8</span><span class="o">:</span>   <span class="n">LUT_out</span> <span class="o">=</span>  <span class="err">'</span><span class="n">sd45</span><span class="p">;</span>    
             <span class="err">'</span><span class="n">sd9</span><span class="o">:</span>   <span class="n">LUT_out</span> <span class="o">=</span>  <span class="err">'</span><span class="n">sd41</span><span class="p">;</span>    
             <span class="err">'</span><span class="n">sd10</span><span class="o">:</span>  <span class="n">LUT_out</span> <span class="o">=</span>  <span class="err">'</span><span class="n">sd37</span><span class="p">;</span>   
             <span class="err">'</span><span class="n">sd11</span><span class="o">:</span>  <span class="n">LUT_out</span> <span class="o">=</span>  <span class="err">'</span><span class="n">sd33</span><span class="p">;</span>   
             <span class="err">'</span><span class="n">sd12</span><span class="o">:</span>  <span class="n">LUT_out</span> <span class="o">=</span>  <span class="err">'</span><span class="n">sd30</span><span class="p">;</span>   
             <span class="err">'</span><span class="n">sd13</span><span class="o">:</span>  <span class="n">LUT_out</span> <span class="o">=</span>  <span class="err">'</span><span class="n">sd27</span><span class="p">;</span>   
             <span class="err">'</span><span class="n">sd14</span><span class="o">:</span>  <span class="n">LUT_out</span> <span class="o">=</span>  <span class="err">'</span><span class="n">sd25</span><span class="p">;</span>
             <span class="err">'</span><span class="n">sd15</span><span class="o">:</span>  <span class="n">LUT_out</span> <span class="o">=</span>  <span class="err">'</span><span class="n">sd22</span><span class="p">;</span>
            <span class="nl">default:</span> <span class="n">LUT_out</span> <span class="o">=</span>  <span class="err">'</span><span class="n">sd0</span><span class="p">;</span>
        <span class="k">endcase</span>
        <span class="n">NewW</span> <span class="o">=</span> <span class="n">CurrentW</span> <span class="o">+</span> <span class="n">LUT_out_reg</span><span class="p">;</span>
</code></pre></div></div>

<h2 id="optimizing-the-learning-engine">Optimizing the Learning Engine</h2>

<p>Looking at this design, we can identify a few areas for optimization, specifically in the timing difference calculation and the potentiation/depression value calculation. Seeing that the depression values are simply the negative of the potentiation values, we can reduce the LUT size by only storing the absolute weight change values and using a signed flag to determine if the value should be added or subtracted from the current weight. Moreover, we can then simplify the priority encoder size since it only needs to generate the absolute value of the timing difference, rather than both positive and negative values, and add simple logic to generate the signed flag.</p>

<p>Optimizations:</p>

<ul>
  <li>Reduce the Potentiation/Depression LUT size</li>
  <li>Replace a priority encoder with a single-bit, flag signal.</li>
</ul>

<p>This results in the following design
<img src="/images/Optimized_STDP_LE_PL_diagram.png" alt="Optimized STDP Learning Engine" /></p>

<p>Below is the simplified Verilog code for the optimized priority encoder and signed flag logic:</p>
<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">logic</span> <span class="p">[</span><span class="mi">15</span><span class="o">:</span><span class="mi">0</span><span class="p">]</span> <span class="n">data_reg</span><span class="p">;</span>
    <span class="k">always_ff</span> <span class="o">@</span><span class="p">(</span><span class="kt">posedge</span> <span class="n">clk</span><span class="p">)</span> <span class="k">begin</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">rst</span><span class="p">)</span> <span class="k">begin</span>
            <span class="n">data_reg</span> <span class="o">&lt;=</span> <span class="mb">16'b0</span><span class="p">;</span>
            <span class="n">SignedFlag</span> <span class="o">&lt;=</span> <span class="mi">0</span><span class="p">;</span> <span class="c1">// Reset SignedFlag on reset</span>
        <span class="k">end</span> <span class="k">else</span> <span class="k">begin</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">PostSynapticNeuron</span><span class="p">[</span><span class="mi">15</span><span class="p">]</span> <span class="o">==</span> <span class="mi">1</span><span class="p">)</span> <span class="k">begin</span>
                <span class="n">data_reg</span> <span class="o">&lt;=</span> <span class="n">PreSynapticNeuron</span><span class="p">;</span>
                <span class="n">SignedFlag</span> <span class="o">&lt;=</span> <span class="mi">0</span><span class="p">;</span> <span class="c1">// PostSynapticNeuron is active, set SignedFlag</span>
            <span class="k">end</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">PreSynapticNeuron</span><span class="p">[</span><span class="mi">15</span><span class="p">]</span> <span class="o">==</span> <span class="mi">1</span><span class="p">)</span> <span class="k">begin</span>
                <span class="n">data_reg</span> <span class="o">&lt;=</span> <span class="n">PostSynapticNeuron</span><span class="p">;</span>
                <span class="n">SignedFlag</span> <span class="o">&lt;=</span> <span class="mi">1</span><span class="p">;</span> <span class="c1">// PreSynapticNeuron is active, set SignedFlag</span>
            <span class="k">end</span> 
        <span class="k">end</span>
    <span class="k">end</span>

    <span class="k">always_comb</span> <span class="k">begin</span>
        <span class="k">unique</span> <span class="k">casez</span><span class="p">(</span><span class="n">data_reg</span><span class="p">)</span>
            <span class="mb">16'b1???????????????</span><span class="o">:</span> <span class="n">TimingDifference</span> <span class="o">=</span> <span class="mi">4'd0</span><span class="p">;</span> <span class="c1">// 0</span>
            <span class="mb">16'b01??????????????</span><span class="o">:</span> <span class="n">TimingDifference</span> <span class="o">=</span> <span class="mi">4'd1</span><span class="p">;</span> <span class="c1">// 1</span>
            <span class="mb">16'b001?????????????</span><span class="o">:</span> <span class="n">TimingDifference</span> <span class="o">=</span> <span class="mi">4'd2</span><span class="p">;</span> <span class="c1">// 2</span>
            <span class="mb">16'b0001????????????</span><span class="o">:</span> <span class="n">TimingDifference</span> <span class="o">=</span> <span class="mi">4'd3</span><span class="p">;</span> <span class="c1">// 3</span>
            <span class="mb">16'b00001???????????</span><span class="o">:</span> <span class="n">TimingDifference</span> <span class="o">=</span> <span class="mi">4'd4</span><span class="p">;</span> <span class="c1">// 4</span>
            <span class="mb">16'b000001??????????</span><span class="o">:</span> <span class="n">TimingDifference</span> <span class="o">=</span> <span class="mi">4'd5</span><span class="p">;</span> <span class="c1">// 5</span>
            <span class="mb">16'b0000001?????????</span><span class="o">:</span> <span class="n">TimingDifference</span> <span class="o">=</span> <span class="mi">4'd6</span><span class="p">;</span> <span class="c1">// 6</span>
            <span class="mb">16'b00000001????????</span><span class="o">:</span> <span class="n">TimingDifference</span> <span class="o">=</span> <span class="mi">4'd7</span><span class="p">;</span> <span class="c1">// 7</span>
            <span class="mb">16'b000000001???????</span><span class="o">:</span> <span class="n">TimingDifference</span> <span class="o">=</span> <span class="mi">4'd8</span><span class="p">;</span> <span class="c1">// 8</span>
            <span class="mb">16'b0000000001??????</span><span class="o">:</span> <span class="n">TimingDifference</span> <span class="o">=</span> <span class="mi">4'd9</span><span class="p">;</span> <span class="c1">// 9</span>
            <span class="mb">16'b00000000001?????</span><span class="o">:</span> <span class="n">TimingDifference</span> <span class="o">=</span> <span class="mi">4'd10</span><span class="p">;</span> <span class="c1">// 10</span>
            <span class="mb">16'b000000000001????</span><span class="o">:</span> <span class="n">TimingDifference</span> <span class="o">=</span> <span class="mi">4'd11</span><span class="p">;</span> <span class="c1">// 11</span>
            <span class="mb">16'b0000000000001???</span><span class="o">:</span> <span class="n">TimingDifference</span> <span class="o">=</span> <span class="mi">4'd12</span><span class="p">;</span> <span class="c1">// 12</span>
            <span class="mb">16'b00000000000001??</span><span class="o">:</span> <span class="n">TimingDifference</span> <span class="o">=</span> <span class="mi">4'd13</span><span class="p">;</span> <span class="c1">// 13</span>
            <span class="mb">16'b000000000000001?</span><span class="o">:</span> <span class="n">TimingDifference</span> <span class="o">=</span> <span class="mi">4'd14</span><span class="p">;</span> <span class="c1">// 14</span>
            <span class="mb">16'b0000000000000001</span><span class="o">:</span> <span class="n">TimingDifference</span> <span class="o">=</span> <span class="mi">4'd15</span><span class="p">;</span> <span class="c1">// 15</span>
            <span class="nl">default:</span>              <span class="n">TimingDifference</span> <span class="o">=</span> <span class="mi">4'd0</span><span class="p">;</span> <span class="c1">// Default case</span>
        <span class="k">endcase</span> 
    <span class="k">end</span>
</code></pre></div></div>
<p>The potentiation LUT is now reduced to 16 entries, as the depression values are not needed. The adder now takes in the absolute weight change value and a signed flag, which determines if the value should be added/subtracted from the current weight according to potentiation/depression. The adder and LUT can be implemented as follows:</p>
<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">always_comb</span> <span class="k">begin</span>
      <span class="k">unique</span> <span class="k">case</span> <span class="p">(</span><span class="n">potDepIndex</span><span class="p">)</span>
        <span class="mi">4'd0</span><span class="o">:</span> <span class="n">potDepValue</span> <span class="o">=</span> <span class="err">'</span><span class="n">sd0</span><span class="p">;</span>  
        <span class="mi">4'd1</span><span class="o">:</span> <span class="n">potDepValue</span> <span class="o">=</span> <span class="err">'</span><span class="n">sd90</span><span class="p">;</span>    
        <span class="mi">4'd2</span><span class="o">:</span> <span class="n">potDepValue</span> <span class="o">=</span> <span class="err">'</span><span class="n">sd82</span><span class="p">;</span>    
        <span class="mi">4'd3</span><span class="o">:</span> <span class="n">potDepValue</span> <span class="o">=</span> <span class="err">'</span><span class="n">sd74</span><span class="p">;</span>    
        <span class="mi">4'd4</span><span class="o">:</span> <span class="n">potDepValue</span> <span class="o">=</span> <span class="err">'</span><span class="n">sd67</span><span class="p">;</span>    
        <span class="mi">4'd5</span><span class="o">:</span> <span class="n">potDepValue</span> <span class="o">=</span> <span class="err">'</span><span class="n">sd61</span><span class="p">;</span>    
        <span class="mi">4'd6</span><span class="o">:</span> <span class="n">potDepValue</span> <span class="o">=</span> <span class="err">'</span><span class="n">sd55</span><span class="p">;</span>    
        <span class="mi">4'd7</span><span class="o">:</span> <span class="n">potDepValue</span> <span class="o">=</span> <span class="err">'</span><span class="n">sd50</span><span class="p">;</span>    
        <span class="mi">4'd8</span><span class="o">:</span> <span class="n">potDepValue</span> <span class="o">=</span> <span class="err">'</span><span class="n">sd45</span><span class="p">;</span>    
        <span class="mi">4'd9</span><span class="o">:</span> <span class="n">potDepValue</span> <span class="o">=</span> <span class="err">'</span><span class="n">sd41</span><span class="p">;</span>    
        <span class="mi">4'd10</span><span class="o">:</span> <span class="n">potDepValue</span> <span class="o">=</span> <span class="err">'</span><span class="n">sd37</span><span class="p">;</span>   
        <span class="mi">4'd11</span><span class="o">:</span> <span class="n">potDepValue</span> <span class="o">=</span> <span class="err">'</span><span class="n">sd33</span><span class="p">;</span>   
        <span class="mi">4'd12</span><span class="o">:</span> <span class="n">potDepValue</span> <span class="o">=</span> <span class="err">'</span><span class="n">sd30</span><span class="p">;</span>   
        <span class="mi">4'd13</span><span class="o">:</span> <span class="n">potDepValue</span> <span class="o">=</span> <span class="err">'</span><span class="n">sd27</span><span class="p">;</span>   
        <span class="mi">4'd14</span><span class="o">:</span> <span class="n">potDepValue</span> <span class="o">=</span> <span class="err">'</span><span class="n">sd25</span><span class="p">;</span>
        <span class="mi">4'd15</span><span class="o">:</span> <span class="n">potDepValue</span> <span class="o">=</span> <span class="err">'</span><span class="n">sd22</span><span class="p">;</span>   
        <span class="nl">default:</span> <span class="n">potDepValue</span> <span class="o">=</span> <span class="err">'</span><span class="n">sd0</span><span class="p">;</span>  
    <span class="k">endcase</span>
<span class="k">end</span>
   <span class="k">always_comb</span> <span class="k">begin</span>
        <span class="n">NewW</span> <span class="o">=</span> <span class="n">CurrentW</span> <span class="o">+</span> <span class="p">(</span><span class="n">SignedFlag</span> <span class="o">?</span> <span class="o">-</span><span class="n">DeltaW</span> <span class="o">:</span> <span class="n">DeltaW</span><span class="p">);</span> <span class="c1">// SignedFlag = 1 means subtract</span>
    <span class="k">end</span>
</code></pre></div></div>

<h2 id="fpga-utilization">FPGA Utilization</h2>
<p>We designed, synthesized, and implemented the original and optimized STDP learning engines on a Xilinx Zynq-7000 SoC “ZC702” Evaulation board. The following table shows the FPGA resource utilization for both designs:</p>

<table>
  <thead>
    <tr>
      <th>Resource Type</th>
      <th>Original Design</th>
      <th>Optimized Design</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>LUTs</td>
      <td>179</td>
      <td>141</td>
    </tr>
    <tr>
      <td>FFs</td>
      <td>347</td>
      <td>341</td>
    </tr>
    <tr>
      <td>Fmax</td>
      <td>187 MHz</td>
      <td>205 MHz</td>
    </tr>
  </tbody>
</table>

<p>From the table, we can see that the optimized design has reduced LUT utilization by 23.75% and increase the Fmax by 10.25% due to reduction in the critical path, while manintaing the a similar number of flip-flops (FFs).</p>

<h2 id="critical-path-analysis">Critical Path Analysis</h2>
<p>To understand the increase in Fmax, we can analyze the critical path of both designs. The critical path is the longest path delay through the circuit that determines the maximum frequency at which the circuit can operate. In the original design, the critical path reported from Vivado is 5.393 ns as shown in the attached image from Vivado’s Timing Summary.
<img src="/images/BasicEncoderDelay.png" alt="Original Critical Path" />
In the optimized design, the critical path is reduced to 4.801 ns, shown in the Vivado Timing Summary below.
<img src="/images/OptimizedEncoderDelay.png" alt="Optimized Critical Path" /></p>]]></content><author><name>Aaryan Dhawan</name><email>aaryanvaldhawan@gmail.com</email></author><category term="FPGAS" /><category term="Spiking Neural Networks" /><category term="STDP" /><category term="RTL Design" /><summary type="html"><![CDATA[Written by Aaryan Dhawan, in collaboration with Muhammad Farhan Azmine]]></summary></entry></feed>