<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Gursimran's Blog]]></title><description><![CDATA[Gursimran's Blog]]></description><link>https://blog.mixedsignal.tech</link><generator>RSS for Node</generator><lastBuildDate>Mon, 13 Apr 2026 11:38:40 GMT</lastBuildDate><atom:link href="https://blog.mixedsignal.tech/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><atom:link rel="first" href="https://blog.mixedsignal.tech/rss.xml"/><item><title><![CDATA[PyNoetic: Accelerating Brain Computer Interface development.]]></title><description><![CDATA[<h2 id="heading-what-are-bcis">What are BCIs?</h2>
<p>Neural pathways governing muscle control are often compromised in patients diagnosed with neurological disorders such as Cerebral Palsy, Amyotrophic Lateral Sclerosis (ALS), and traumatic brain or spinal cord injuries. Consequently, these patients experience substantial reductions in mobility and communication capabilities, significantly impacting their overall independence, social functioning, and self-care. This abrupt onset of mobility impairment in patients often triggers symptoms of psychological distress like depression, anxiety, and mood disturbances. In response to these challenges, Brain-Computer Interfaces (BCIs) offer a promising solution, establishing an alternative pathway between an individuals brain and the external world, bypassing the compromised nervous system. However, the intricate nature of the human brain, along with characteristic variations that occur over time and between individuals, necessitates the development of BCIs tailored to specific disabilities. Recent studies have indicated that a BCI system designed to assist an individual with a particular disability is unlikely to be suitable for addressing a different one. Furthermore, even within a cohort of individuals sharing the same disability, the performance and effectiveness of a BCI system exhibit significant variability. BCIs developed in controlled lab settings also often lack versatility. Consequently, these solutions have not found widespread applications. To bridge this gap effectively, there is an immediate need for rapid prototyping of BCIs tailored to individual users.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1721999500250/2ee0e9e9-4714-4bf9-ad69-d08a79d6ff0c.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-what-is-pynoetic">What is PyNoetic?</h2>
<p>The development of a BCI system is a multifaceted undertaking that demands expertise across multiple domains, including neuroscience, digital signal processing, machine learning, artificial intelligence, and embedded systems. Testing experimental paradigms further requires coding complex software frameworks, posing a significant hurdle to the swift development of scalable BCI solutions.</p>
<p>PyNoetic is a novel open-source, highly customizable, Graphical User Interface (GUI)-aided BCI framework built in Python. The primary objective of PyNoetic is to expedite the development and prototyping of synchronous BCIs. Addressing substantial shortcomings found in previous BCI frameworks, PyNoetic aims to provide a stand-alone solution to researchers, offering capabilities ranging from stimuli presentation and data acquisition to classification and feedback.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1722001102206/a84d1eaa-739e-4b07-9e05-8ee1aa31124c.png" alt class="image--center mx-auto" /></p>
<p>One of PyNoetics key strengths lies in its versatility for both offline analysis and real-time BCI development. By catering to both programmers and non-programmers, it streamlines the experimental design process, enabling researchers to focus on more intricate facets of BCI development and accelerating research. An introductory video of PyNoetic is available on <a target="_blank" href="https://www.youtube.com/watch?v=imYeke55XvA">YouTube</a>.</p>
<h2 id="heading-getting-started-with-pynoetic">Getting Started with PyNoetic.</h2>
<p>PyNoetic's source code is available on <a target="_blank" href="https://github.com/NeuroDiag/PyNoetic-official">GitHub</a>.</p>
<pre><code class="lang-bash">git <span class="hljs-built_in">clone</span> https://github.com/NeuroDiag/PyNoetic-official.git
python -m venv PyNoeticEnv
PyNoeticEnv/Scripts/activate
pip install -r requirements.txt
<span class="hljs-comment"># You might need to use: sudo apt install libxcb==* for Linux</span>
<span class="hljs-built_in">cd</span> gui
python load.py
</code></pre>
<h2 id="heading-pynoetic-features">PyNoetic Features</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1722001969114/12b95325-40b3-4b04-800a-65bd8c399b1a.png" alt class="image--center mx-auto" /></p>
<p>PyNoetic's features are divided into modules and submodules for ease of use and understanding. There are six primary modules :</p>
<ol>
<li><p>Stimuli Generation and Data Recording - Lab Streaming Layer for data acquisition and the ability to create custom experiments for SSVEL/ERP-based BCI tasks.</p>
</li>
<li><p>Channel Selection - Various channel ranking algorithms to identify critical channels offline and reduce complexity during deployment.</p>
</li>
<li><p>Pre-processing - Programmable filters as well as blind source separation and decomposition-based methods to reject artifacts.</p>
</li>
<li><p>Feature Extraction - Temporal, Frequency, and Spatial domain features. If a feature is missing, submit a <a target="_blank" href="https://github.com/NeuroDiag/PyNoetic-official/issues">request here</a>!</p>
</li>
<li><p>Classification - Popular deep learning models - ResNet, AlexNet, and EEGNet are already included - other models can be added quite easily.</p>
</li>
<li><p>Simulation and Feedback - A 3D simulation environment that allows you to test your pipeline.</p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1763812764641/2cfdadc6-05d1-415c-ab87-6fcb3e5e9a2b.png" alt class="image--center mx-auto" /></p>
</li>
</ol>
<h2 id="heading-why-pynoetic">Why PyNoetic?</h2>
<p>Apart from the standard functionality found in every BCI software, PyNoetic also offers a live mode for developing real-time BCI pipelines without writing a single line of code using programmable flowcharts. This feature is a first in any Python toolbox for BCI development.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1723301794380/66de8bba-7580-4072-9d73-da0610c7e27a.png" alt class="image--center mx-auto" /></p>
<p>Here is a comparison of PyNoetic with some other popular toolboxes.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1763812933025/934d5a65-6b35-4b76-817f-aa1ead5f42eb.png" alt class="image--center mx-auto" /></p>
<p>This table is from <a target="_blank" href="https://journals.plos.org/plosone/article?id=10.1371/journal.pone.0327791">our paper</a>, and you can find more details on the comparison with other toolboxes there.</p>
<h2 id="heading-citing-pynoetic">Citing PyNoetic</h2>
<p>If you find our work valuable for your project, please consider adding a star to <a target="_blank" href="https://github.com/NeuroDiag/PyNoetic-official">the repository</a> and citing the paper in your research.</p>
]]></description><link>https://blog.mixedsignal.tech/pynoetic</link><guid isPermaLink="true">https://blog.mixedsignal.tech/pynoetic</guid><category><![CDATA[eeg]]></category><category><![CDATA[Brain-Computer Interfaces ]]></category><category><![CDATA[Python]]></category><dc:creator><![CDATA[Gursimran Singh]]></dc:creator></item><item><title><![CDATA[Digital Hardware Design : Finite State Machines]]></title><description><![CDATA[<h2 id="heading-what-is-a-finite-state-machine">What is a Finite State Machine?</h2>
<p>FSMs are used to model systems that transit between a finite number of internal states. The transitions between different states depend on the current state and the external input. Hence FSMs are sequential circuits. Practically, FSMs are used as controllers of a larger digital system, examining the external input and current status to activate the appropriate control signals for rest of the system.</p>
<p>FSMs can also be part of an Analog system, helping calibrate analog components to improve performance in certain use cases.</p>
<h2 id="heading-sequential-circuits">Sequential Circuits</h2>
<p>A sequential circuit is essentially a circuit with memory. While in combinational circuits the output depends merely on the input, in sequential circuits the output is a function of both the input and the internal memory of the circuit. In practice, all the storage elements are synchronized to a single clock and the data is sampled with respect to this global clock. This is known as <strong>the synchronized design methodology</strong>.</p>
<p>Basic block diagram of a sequential circuit looks something like this.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1736957906435/1824f885-d426-4a33-9147-4ca47cf53769.png" alt class="image--center mx-auto" /></p>
<p>Code development follows separating the memory element (state register) and then the rest of the circuit is purely combinational similar to what we covered in the last blog.</p>
<h2 id="heading-mealy-and-moore">Mealy and Moore</h2>
<p>FSMs can further be classified into <em>Mealy</em> and <em>Moore Machines.</em> Block diagram of an FSM that elucidates the difference between <em>Mealy</em> and <em>Moore Machines</em> shown below.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1737000776146/dc904e68-5f23-4f23-b94b-8e1a29b59357.png" alt class="image--center mx-auto" /></p>
<p>An FSM is a Mealy machine if the output is a function of the external input and the internal state. Compared to that output of a moore machine only depends on the internal state.</p>
<h2 id="heading-fsm-basics">FSM Basics</h2>
<h3 id="heading-state-diagram">State Diagram</h3>
<p>There are a multitude of ways to describe FSMs, from state diagrams and tables to algorithmic state machine (ASM) charts. All methods however have the same goal, to capture the FSMs inputs, output and conditions for transitions between different states.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1737085260397/d256217e-c62b-415f-bf12-f4e105bc3e15.png" alt class="image--center mx-auto" /></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">This image is generated using a python script that parses the verilog code to generate a state diagram!</div>
</div>

<h3 id="heading-fsm-code-development">FSM Code Development</h3>
<p>Similar to a sequential circuit we first try to separate the memory element and then write the combinational next state logic. The memory element in an FSM is nothing but the state register, to have symbolic state names we use the enumerated data type.</p>
<pre><code class="lang-verilog"><span class="hljs-keyword">typedef</span> <span class="hljs-keyword">enum</span> {s0, s1, s2} state_type;
state_type state_reg, state_next;
</code></pre>
<div data-node-type="callout">
<div data-node-type="callout-emoji"></div>
<div data-node-type="callout-text">Enum is a System Verilog feature. We must mimic the work of enum data type with constant definitions. This gets tedious with larger FSMs.</div>
</div>

<pre><code class="lang-verilog"><span class="hljs-keyword">localparam</span> [<span class="hljs-number">1</span>:<span class="hljs-number">0</span>] s0 = <span class="hljs-number">2'b00</span>, s1 = <span class="hljs-number">2'b01</span>, s2 = <span class="hljs-number">2'b10</span>;
</code></pre>
<p>When an FSM is realized on hardware, the symbolic state names get mapped to binary representations. This process is called <em>state encoding</em>. By default System Verilog maps the enumerated data type to 32 bit Integers. The unused bits are discarded by the software during synthesis.</p>
<h2 id="heading-your-first-fsm-rising-edge-detector">Your First FSM - Rising Edge Detector</h2>
<h3 id="heading-state-diagram-1">State Diagram</h3>
<p>The figure below shows a state diagram of an edge detector based on a Moore machine.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1734548561081/2a17e15e-ece1-44fb-baa5-85a39a9dc9b9.png" alt class="image--center mx-auto" /></p>
<p>The <strong>zero</strong> and <strong>one</strong> states indicate the signal level, the <strong>edg</strong> state indicates movement from zero to one.</p>
<h3 id="heading-system-verilog-code">System Verilog Code</h3>
<pre><code class="lang-verilog"><span class="hljs-keyword">module</span> moore_rising_edge
(
    <span class="hljs-keyword">input</span> <span class="hljs-keyword">logic</span> clk, reset,
    <span class="hljs-keyword">input</span> <span class="hljs-keyword">logic</span> level,
    <span class="hljs-keyword">output</span> <span class="hljs-keyword">logic</span> tick
);

<span class="hljs-keyword">typedef</span> <span class="hljs-keyword">enum</span> {zero, edg, one} state_type;
state_type state_reg, state_next;

<span class="hljs-keyword">always_ff</span> @( <span class="hljs-keyword">posedge</span> clk, <span class="hljs-keyword">posedge</span> reset )
    <span class="hljs-keyword">if</span> (reset)
        state_reg &lt;= <span class="hljs-number">0</span>;
    <span class="hljs-keyword">else</span>
        state_reg &lt;= state_next;

<span class="hljs-keyword">always_comb</span> 
<span class="hljs-keyword">begin</span>
    state_next = state_reg;
    tick = <span class="hljs-number">1'b0</span>;
    <span class="hljs-keyword">case</span> (state_reg)
        zero:
            <span class="hljs-keyword">if</span> (level)
                state_next = edg;
        edg :
        <span class="hljs-keyword">begin</span>
            tick = <span class="hljs-number">1'b1</span>;
            <span class="hljs-keyword">if</span> (level)
                state_next = one;
            <span class="hljs-keyword">else</span>
                state_next = zero;
        <span class="hljs-keyword">end</span>

        one:
            <span class="hljs-keyword">if</span>(~level)
                state_next = zero;
        <span class="hljs-keyword">default</span>: state_next = zero;
    <span class="hljs-keyword">endcase</span>
<span class="hljs-keyword">end</span>


<span class="hljs-keyword">initial</span> <span class="hljs-keyword">begin</span>
    <span class="hljs-built_in">$dumpfile</span>(<span class="hljs-string">"fsm.vcd"</span>);
    <span class="hljs-built_in">$dumpvars</span>;
<span class="hljs-keyword">end</span>

<span class="hljs-keyword">endmodule</span>
</code></pre>
<h3 id="heading-python-test-bench">Python Test bench</h3>
<p>As is with the rest of my blogs so far, we will use cocotb to get some quick results.</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> cocotb
<span class="hljs-keyword">from</span> cocotb.clock <span class="hljs-keyword">import</span> Clock
<span class="hljs-keyword">from</span> cocotb.triggers <span class="hljs-keyword">import</span> RisingEdge
<span class="hljs-keyword">from</span> cocotb.types <span class="hljs-keyword">import</span> LogicArray
<span class="hljs-keyword">from</span> cocotb.triggers <span class="hljs-keyword">import</span> Timer, RisingEdge, ReadOnly, NextTimeStep, FallingEdge

<span class="hljs-meta">@cocotb.test()</span>
<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">test_rising_edge</span>(<span class="hljs-params">dut</span>):</span>

    clock = Clock(dut.clk, <span class="hljs-number">1</span>, units=<span class="hljs-string">"ns"</span>)
    cocotb.start_soon(clock.start(start_high=<span class="hljs-literal">False</span>))
    dut.reset = <span class="hljs-number">0</span>
    dut.level = <span class="hljs-number">0</span>
    <span class="hljs-keyword">await</span> Timer(<span class="hljs-number">10</span>,<span class="hljs-string">'ns'</span>)
    <span class="hljs-comment"># Assert initial output is unknown</span>
    dut.level = <span class="hljs-number">1</span>
    <span class="hljs-keyword">await</span> Timer(<span class="hljs-number">10</span>,<span class="hljs-string">'ns'</span>)
</code></pre>
<h3 id="heading-waveform">Waveform</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1737136098282/af678ca8-0847-4c46-a5cc-99dcea9c2a5b.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-a-look-inside">A Look Inside</h2>
<p>I am a big fan of visualizing the circuit resulting from RTL synthesis. Yosys is a tool I used in my last blog but it has limited System Verilog support. The solution is <a target="_blank" href="https://github.com/chipsalliance/synlig">synlig</a> : a kind of plugin that extends the capabilities of Yosys. Assuming you already have Yosys installed (refer to the <a target="_blank" href="https://blog.mixedsignal.tech/digital-hardware-design-understanding-combinational-circuits">previous blog</a> if you dont), installation is pretty simple.</p>
<pre><code class="lang-bash">apt install -y jq curl wget tk
curl https://api.github.com/repos/chipsalliance/synlig/releases/latest | jq -r <span class="hljs-string">'.assets | .[] | select(.name | startswith("synlig")) | .browser_download_url'</span> | xargs wget -O - | tar -xz
<span class="hljs-built_in">export</span> PATH=`<span class="hljs-built_in">pwd</span>`/synlig:<span class="hljs-variable">$PATH</span>
</code></pre>
<p>Usage is similar to Yosys.</p>
<pre><code class="lang-bash">synlig
<span class="hljs-comment"># read input file</span>
read_systemverilog filename.sv
<span class="hljs-comment"># convert to DFFs and muxes</span>
proc
<span class="hljs-comment"># perform some optimization</span>
opt
<span class="hljs-comment"># visualize the design</span>
show
</code></pre>
<p>We have a case statement and some if statements inside the case statement. So we should have some kind of priority routing network inside of a multiplexing network along with something to store our state in.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1737138559203/f0767412-0706-4b25-9d6b-d5deb93d56b9.png" alt class="image--center mx-auto" /></p>
<p>And that is what we get!</p>
<h2 id="heading-parting-thoughts">Parting Thoughts</h2>
<p>This was a slightly more complicated blog as compared to my usual blogs but I feel that is the nature of hardware design, it gets really hard before getting really easy. The exponential charging curve is not just for capacitors. As usual, appreciate any feedback you guys can send my way and all the code is on <a target="_blank" href="https://github.com/mixed-signal/Digital-System-Design">GitHub</a>.</p>
<p>In the next blog, we will be synthesize some design for an FPGA and actually get it running on the FPGA so stay tuned for that!</p>
]]></description><link>https://blog.mixedsignal.tech/digital-hardware-design-finite-state-machines</link><guid isPermaLink="true">https://blog.mixedsignal.tech/digital-hardware-design-finite-state-machines</guid><category><![CDATA[fsm]]></category><category><![CDATA[VLSI circuit design]]></category><category><![CDATA[verilog]]></category><dc:creator><![CDATA[Gursimran Singh]]></dc:creator></item><item><title><![CDATA[Digital Hardware Design : Understanding Combinational Circuits.]]></title><description><![CDATA[<p>The first time I looked at some RTL, I saw a fair amount of programming constructsquite similar to the if and switch statements familiar to most programmers. As a software engineer, you can pretty much use the two statements interchangeably. However, there is some difference when it comes to hardware.</p>
<p>In this blog, I try to break down these programming constructs into basic combinational circuits using Yosys, an open-source tool for synthesis.</p>
<h2 id="heading-always-block-for-combinational-circuits">Always block for Combinational Circuits</h2>
<p>In my last blog I mentioned that HDLs usually follow a concurrent hardware model and that is true but you can achieve procedural execution in Verilog using something called as the "<em>always"</em> block.</p>
<pre><code class="lang-verilog"><span class="hljs-keyword">always</span> @([senstivity_list])
<span class="hljs-keyword">begin</span>
<span class="hljs-comment">// procedural statements</span>
<span class="hljs-keyword">end</span>
</code></pre>
<p>The procedural statements inside the <em>always</em> block get executed when one of the signals in the senstivity list changes value. Here's an example of a block that generates a pulse width modulated signal.</p>
<pre><code class="lang-verilog"><span class="hljs-keyword">module</span> pwm_gen(
    <span class="hljs-keyword">input</span> [<span class="hljs-number">7</span>:<span class="hljs-number">0</span>]Dutycycle,
    <span class="hljs-keyword">input</span> clk, 
    <span class="hljs-keyword">output</span> <span class="hljs-keyword">reg</span> [<span class="hljs-number">7</span>:<span class="hljs-number">0</span>] counter, 
    <span class="hljs-keyword">output</span> <span class="hljs-keyword">reg</span> pwmout
);

<span class="hljs-keyword">always</span> @(<span class="hljs-keyword">posedge</span> clk) <span class="hljs-keyword">begin</span>
    <span class="hljs-keyword">if</span>(counter &lt; <span class="hljs-number">99</span>)
        counter &lt;= counter + <span class="hljs-number">1</span>;
    <span class="hljs-keyword">else</span> 
        counter &lt;= <span class="hljs-number">0</span>;
<span class="hljs-keyword">end</span>

<span class="hljs-keyword">always</span> @(<span class="hljs-keyword">posedge</span> clk) <span class="hljs-keyword">begin</span>
    <span class="hljs-keyword">if</span>(counter &lt; Dutycycle) 
        pwmout &lt;= <span class="hljs-number">1'b1</span>;
    <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (counter == <span class="hljs-number">99</span>) 
        pwmout &lt;= <span class="hljs-number">1'b0</span>;
    <span class="hljs-keyword">else</span>
        pwmout &lt;= <span class="hljs-number">1'b0</span>;
<span class="hljs-keyword">end</span>         
<span class="hljs-keyword">endmodule</span>
</code></pre>
<p>You can see that the senstivity list has the positive edge of the clock signal so the always block executes everytime there is a positive edge on the clock and we see the counter signal increase.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1723303386289/a68f3eca-f655-4318-8b5b-877ddad0c252.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-logic-synthesis-with-yosys">Logic Synthesis with Yosys</h2>
<p>Once you have a verilog file, you can use Yosys to visualize the design. Yosys is an open source logic synthesis tool starting from RTL netlist and finally to gates in the target technology.</p>
<p>While constructs such as if, switch in a language like C are executed sequentially, these constructs in verilog are realised using combinational circuits which have no sequential control and are therefore realised using <strong><em>routing networks</em></strong>. All the expressions in a routing network are evaluated concurrently and the desired result is routed to the output. We'll use yosys to understand the routing structure of common programming constructs.</p>
<pre><code class="lang-bash"><span class="hljs-comment"># installing yosys</span>
sudo apt-get install yosys
<span class="hljs-comment"># yosys interactive mode</span>
yosys
<span class="hljs-comment"># read input file</span>
read_verilog filename.v
<span class="hljs-comment"># convert to DFFs and muxes</span>
proc
<span class="hljs-comment"># perform some optimization</span>
opt
<span class="hljs-comment"># visualize the design</span>
show
</code></pre>
<p>You can also create a script for Yosys by pasting all the commands in a .ys file.</p>
<pre><code class="lang-bash">yosys synth.ys
</code></pre>
<p>Result of yosys script for the pwm_gen module gives something like this.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1723319874320/cfc78383-18f8-4fba-a030-55455f7101f3.png" alt class="image--center mx-auto" /></p>
<p>More information about Yosys can be found <a target="_blank" href="https://yosyshq.readthedocs.io/projects/yosys/en/latest/index.html">here</a>.</p>
<h2 id="heading-if-statement">If Statement</h2>
<p>The previous example of a PWM generator uses an if statement in the <em>always</em> block. What does that translate to on the hardware? Let's find out using Yosys. To that end let us take the simple example of a n-to-2^n decoder with n = 2.</p>
<p>Truth table of 2-to-4 decoder with enable is as follows :</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td>en</td><td>a[1]</td><td>a[0]</td><td>y[3:0]</td></tr>
</thead>
<tbody>
<tr>
<td>0</td><td>-</td><td>-</td><td>0000</td></tr>
<tr>
<td>1</td><td>0</td><td>0</td><td>0001</td></tr>
<tr>
<td>1</td><td>0</td><td>1</td><td>0010</td></tr>
<tr>
<td>1</td><td>1</td><td>0</td><td>0100</td></tr>
<tr>
<td>1</td><td>1</td><td>1</td><td>1000</td></tr>
</tbody>
</table>
</div><pre><code class="lang-verilog"><span class="hljs-keyword">module</span> decoder (
    <span class="hljs-keyword">input</span> <span class="hljs-keyword">wire</span> [<span class="hljs-number">1</span>:<span class="hljs-number">0</span>] a,
    <span class="hljs-keyword">output</span> <span class="hljs-keyword">reg</span> [<span class="hljs-number">3</span>:<span class="hljs-number">0</span>] y,
    <span class="hljs-keyword">input</span> <span class="hljs-keyword">wire</span> en
);

<span class="hljs-keyword">always</span> @ * <span class="hljs-keyword">begin</span>
    <span class="hljs-keyword">if</span> (en == <span class="hljs-number">1'b0</span>)
        y = <span class="hljs-number">4'b0000</span>;
    <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (a == <span class="hljs-number">2'b00</span>)
        y = <span class="hljs-number">4'b0001</span>;
    <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (a == <span class="hljs-number">2'b01</span>)
        y = <span class="hljs-number">4'b0010</span>;
    <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (a == <span class="hljs-number">2'b10</span>)
        y = <span class="hljs-number">4'b0100</span>;
    <span class="hljs-keyword">else</span>
        y = <span class="hljs-number">4'b1000</span>;
<span class="hljs-keyword">end</span>

<span class="hljs-keyword">endmodule</span>
</code></pre>
<h3 id="heading-routing-structure">Routing Structure</h3>
<p>The if-else statement implies a priority routing network in verilog. It is implemented by a sequence of 2-to-1 multiplexers as showing in the figure below.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1723304723585/28cf975e-7bdc-4075-bb8e-c19d687e24b1.png" alt class="image--center mx-auto" /></p>
<p>The four 2-to-1 multiplexors form the priority routing network and other components represent the boolean/arithmetic expressions apart from the if-else ladder. The number of muxes increases propotionally to the number of if statements and a large number of if-else statements can cause a significant propogation delay.</p>
<h2 id="heading-case-statement">Case Statement</h2>
<pre><code class="lang-verilog"><span class="hljs-keyword">module</span> decode_case (
    <span class="hljs-keyword">input</span> <span class="hljs-keyword">wire</span> [<span class="hljs-number">1</span>:<span class="hljs-number">0</span>] a,
    <span class="hljs-keyword">output</span> <span class="hljs-keyword">reg</span> [<span class="hljs-number">3</span>:<span class="hljs-number">0</span>] y,
    <span class="hljs-keyword">input</span> <span class="hljs-keyword">wire</span> en
);

<span class="hljs-keyword">always</span> @ * <span class="hljs-keyword">begin</span>
    <span class="hljs-keyword">case</span> ({en, a})
    <span class="hljs-number">3'b000</span>, <span class="hljs-number">3'b001</span>, <span class="hljs-number">3'b010</span>, <span class="hljs-number">3'b011</span>: y = <span class="hljs-number">4'b0000</span>;
    <span class="hljs-number">3'b100</span>: y = <span class="hljs-number">4'b0001</span>;
    <span class="hljs-number">3'b101</span>: y = <span class="hljs-number">4'b0010</span>;
    <span class="hljs-number">3'b110</span>: y = <span class="hljs-number">4'b0100</span>;
    <span class="hljs-number">3'b111</span>: y = <span class="hljs-number">4'b1000</span>;
    <span class="hljs-keyword">endcase</span>

<span class="hljs-keyword">end</span>

<span class="hljs-keyword">endmodule</span>
</code></pre>
<h3 id="heading-routing-structure-1">Routing Structure</h3>
<p>The case statement implies a multiplexing network and you can see how implementation of the same decoder results in two different circuits based on the programming construct used.</p>
<p>The pmux in the figure below represents a priority mux which can be thought of as a series of cascaded multiplexors used in the if statement or as a single n-to-1 multiplexer. Each value of the case expression can be mapped to one input of an n-to-1 multiplexer. Here, the number of inputs in the multiplexer would increase with the number of case expressions.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1723308684791/076c4d2a-98c2-4ed0-8044-ff991ad34f6d.png" alt class="image--center mx-auto" /></p>
<p>As usual the code and other files are in <a target="_blank" href="https://github.com/mixed-signal/Digital-System-Design"><strong>this github repo.</strong></a></p>
<h2 id="heading-parting-thoughts"><strong>Parting thoughts</strong></h2>
<p>We checked out two routing structures in this blog and both implementations have tradeoffs. Priority routing would be benficial when there is some kind of weightage to the cases. Multiplexing networks would shine where the implementation is more truth-table oriented.</p>
<p>Let me know what you guys thought of this one. Feedback is always appreciated.</p>
]]></description><link>https://blog.mixedsignal.tech/digital-hardware-design-understanding-combinational-circuits</link><guid isPermaLink="true">https://blog.mixedsignal.tech/digital-hardware-design-understanding-combinational-circuits</guid><category><![CDATA[verilog]]></category><category><![CDATA[Open Source]]></category><category><![CDATA[VLSI circuit design]]></category><dc:creator><![CDATA[Gursimran Singh]]></dc:creator></item><item><title><![CDATA[Digital Hardware Design : From Zero to One]]></title><description><![CDATA[<p>I recently started delving into some projects related digital circuits at work and I found myself back in tutorial hell. Took me some time but I was finally able to make some progress on the digital design front. By all means, I am no expert but I'll be sharing what I think is a fairly fast way to get started with digital design.</p>
<h2 id="heading-verilog-hardware-description-language">Verilog : Hardware Description Language</h2>
<p>Syntactically Verilog is similar to C/C++ but semantically the language is based on concurrent hardware operation which is very different from sequential execution of C/C++. Just like in any other language, there are many different ways of achieving a result but the focus of this blog series is to quickly get to a point where we are able to design hardware. So i'll try to come up with a verilog skeleton that we can use to generate hardware that is synthesizable in a better-safe-than-sorry approach.</p>
<h2 id="heading-setting-up-the-environment">Setting up the environment</h2>
<p>I'm a big fan of open-source tools and running stuff locally on my machine rather than on servers. You could get by using an online verilog compiler but i'll be using Icarus Verilog, GTKWave and CocoTB to simulate, view waveforms and write testbenches respectively. To set this environment up, you can refer to <a target="_blank" href="https://blog.mixedsignal.tech/getting-started-with-open-source-design-verification-with-icarus-verilog-and-cocotb">one of my previous blogs.</a></p>
<h2 id="heading-verilog-skeleton">Verilog Skeleton</h2>
<pre><code class="lang-verilog"><span class="hljs-keyword">module</span> modulename
<span class="hljs-comment">// Port Declration</span>
(
<span class="hljs-keyword">input</span> <span class="hljs-keyword">wire</span> in0, in1,
<span class="hljs-keyword">output</span> <span class="hljs-keyword">wire</span> out0
);
<span class="hljs-comment">// Internal Signal Declaration</span>
<span class="hljs-keyword">wire</span> sig0, sig1;
<span class="hljs-comment">// Block logic</span>
<span class="hljs-keyword">assign</span> out0 = sig0 &amp; sig1;
<span class="hljs-keyword">assign</span> sig0 = in0 &amp; in1;
<span class="hljs-keyword">assign</span> sig1 = ~in0 &amp; ~in1;

<span class="hljs-keyword">endmodule</span>
</code></pre>
<p>The above is a sample verilog code, we'll try to understand the basic syntax of the language used in this example and i'll leave it upto the reader to figure out the syntax in future examples as we move forward.</p>
<h3 id="heading-port-declaration">Port Declaration</h3>
<p>The port declaration specifies the modes, data-types and names of the module's I/O. Modes are typically input, output or inout, data-type is usually wire but other data-types like reg, realtime, integer exist but not all of them can be physically synthesized.</p>
<h3 id="heading-internal-signal-declaration">Internal Signal Declaration</h3>
<p>This section specifies the internal signals and parameters and can be thought of as the internal wires connecting various circuit parts in a module.</p>
<h3 id="heading-module-logic">Module Logic</h3>
<p>This is the program body of a verilog module and can be thought of as a combination of circuit parts that execute concurrently. There are several ways to describe a circuit part. We have used continuous assignment in the example above but there are other ways like the "Always Block" that are used in more complicated circuits.</p>
<h2 id="heading-testbench">Testbench</h2>
<p>Once a module is developed, it can be simulated to verify functional correctness. Usually in companies there's a whole another team to run thorough checks using simulation where they use things like UVM, etc. But once you write code it's still worthwhile to do some basic checks on your own. Simulation is usually performed with the same HDL framework but we're seeing more options availble like cocoTb that allows you to write your test bench in python rather than verilog which gives you access to more advanced computation libraries like numpy, pytorch and scikit-learn.</p>
<pre><code class="lang-verilog"><span class="hljs-meta">`<span class="hljs-meta-keyword">timescale</span> 1ns/10ps</span>

<span class="hljs-keyword">module</span> modulename_testbench;
    <span class="hljs-keyword">reg</span> test_in0, test_in1;
    <span class="hljs-keyword">wire</span> test_out;

    modulename uut(<span class="hljs-variable">.in0</span>(test_in0), <span class="hljs-variable">.in1</span>(test_in1), <span class="hljs-variable">.out0</span>(test_out));

    <span class="hljs-keyword">initial</span> <span class="hljs-keyword">begin</span>
        <span class="hljs-built_in">$dumpfile</span>(<span class="hljs-string">"sample.vcd"</span>);
        <span class="hljs-built_in">$dumpvars</span>(<span class="hljs-number">0</span>, modulename_testbench);
        <span class="hljs-comment">// Test Vector</span>
        test_in0 = <span class="hljs-number">1'b0</span>;
        test_in1 = <span class="hljs-number">1'b0</span>;
        <span class="hljs-comment">// Wait time</span>
        # <span class="hljs-number">100</span>;
        test_in0 = <span class="hljs-number">1'b1</span>;
        test_in1 = <span class="hljs-number">1'b0</span>;
        # <span class="hljs-number">100</span>;
        test_in0 = <span class="hljs-number">1'b0</span>;
        test_in1 = <span class="hljs-number">1'b1</span>;
        # <span class="hljs-number">100</span>;
        test_in0 = <span class="hljs-number">1'b1</span>;
        test_in1 = <span class="hljs-number">1'b1</span>;
        # <span class="hljs-number">100</span>;
        <span class="hljs-built_in">$finish</span>();
    <span class="hljs-keyword">end</span>
<span class="hljs-keyword">endmodule</span>
</code></pre>
<h2 id="heading-simulation-verilog">Simulation - Verilog</h2>
<p>If you're a college student you probably have access to some kind of tools like Cadence Xcelium or Vivado but if you don't have access to those tools and still would like to simulate your circuit, Icarus Verilog is pretty good. You won't be able to simulate a full fledged AMS design but purely digital designs should not be an issue.</p>
<pre><code class="lang-bash">iverilog -o samp modulename.v modulename_testbench.v
vvp sample
gtkwave sample.vcd
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1721209406327/296cb20c-601f-4bb2-8477-0ce1f4181e3e.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-simulation-cocotb">Simulation - Cocotb</h2>
<p>To simulate with cocotb we do not need to write a testbench in Verilog. But if you remember we were using the testbench to also generate the VCD file to view the waveform.</p>
<pre><code class="lang-verilog"><span class="hljs-keyword">module</span> modulename
<span class="hljs-comment">// Port Declration</span>
(
<span class="hljs-keyword">input</span> <span class="hljs-keyword">wire</span> in0, in1,
<span class="hljs-keyword">output</span> <span class="hljs-keyword">wire</span> out0
);
<span class="hljs-comment">// Internal Signal Declaration</span>
<span class="hljs-keyword">wire</span> sig0, sig1;
<span class="hljs-comment">// Block logic</span>
<span class="hljs-keyword">assign</span> out0 = sig0 &amp; sig1;
<span class="hljs-keyword">assign</span> sig0 = in0 &amp; in1;
<span class="hljs-keyword">assign</span> sig1 = ~in0 &amp; ~in1;

<span class="hljs-keyword">initial</span> <span class="hljs-keyword">begin</span>
    <span class="hljs-built_in">$dumpfile</span>(<span class="hljs-string">"waves.vcd"</span>);
    <span class="hljs-built_in">$dumpvars</span>;
<span class="hljs-keyword">end</span>

<span class="hljs-keyword">endmodule</span>
</code></pre>
<p>The python test bench looks something like this.</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> cocotb
<span class="hljs-keyword">from</span> cocotb.triggers <span class="hljs-keyword">import</span> Timer, RisingEdge

<span class="hljs-meta">@cocotb.test()</span>
<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">test_modulename</span>(<span class="hljs-params">dut</span>):</span>
    a = (<span class="hljs-number">0</span>,<span class="hljs-number">1</span>,<span class="hljs-number">0</span>,<span class="hljs-number">1</span>)
    b = (<span class="hljs-number">0</span>,<span class="hljs-number">0</span>,<span class="hljs-number">1</span>,<span class="hljs-number">1</span>)
    y = (<span class="hljs-number">0</span>,<span class="hljs-number">1</span>,<span class="hljs-number">1</span>,<span class="hljs-number">0</span>)

    <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(<span class="hljs-number">4</span>):
        dut.in0.value = a[i]
        dut.in1.value = b[i]
        <span class="hljs-keyword">await</span> Timer(<span class="hljs-number">10</span>, <span class="hljs-string">'ns'</span>)
        <span class="hljs-comment"># assert dut.out0.value == y[i], f"Error at iteration {i}"</span>
</code></pre>
<p>The assert statement can be used to make the simulation "stop on fail" where it matches the "out0" signal to an element in array y.</p>
<p>Cocotb makefile and other additional files are in <a target="_blank" href="https://github.com/mixed-signal/Digital-System-Design">this github repo.</a></p>
<h2 id="heading-parting-thoughts">Parting thoughts</h2>
<p>This was the first blog and I hope to write more as I learn more about digital design, there's alot of interesting topics that I would like to discuss like BIST, DfT in due time.</p>
<p>Let me know what you guys thought about this one. Feedback is always appreciated.</p>
]]></description><link>https://blog.mixedsignal.tech/digital-hardware-design-from-zero-to-one</link><guid isPermaLink="true">https://blog.mixedsignal.tech/digital-hardware-design-from-zero-to-one</guid><category><![CDATA[DIGITAL SYSTEM DESIGN]]></category><category><![CDATA[Python]]></category><category><![CDATA[verilog]]></category><dc:creator><![CDATA[Gursimran Singh]]></dc:creator></item><item><title><![CDATA[The "Hello World!" of Design Verification.]]></title><description><![CDATA[<p>The world of programming is often introduced to new students with a program that prints "Hello World!" on a screen. In the world of embedded students are made to blink an LED. It's essentially a basic exercise that you can build upon to understand most if not all concepts of a particular field.</p>
<p>Similarly in the world of digital circuits, a NOT gate is the most basic circuit out there.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1711301424350/2cc40d80-c239-42d1-844f-f0d0c401b630.png" alt class="image--center mx-auto" /></p>
<p>But with just one input and one output, it does not give a whole lot of room to play around and I personally am a big fan of XOR gate.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1711301936491/a42c7cac-1dcd-4ea7-a632-30f01444ed67.png" alt class="image--center mx-auto" /></p>
<div class="hn-table">
<table>
<thead>
<tr>
<td>A</td><td>B</td><td>Y</td></tr>
</thead>
<tbody>
<tr>
<td>0</td><td>0</td><td>0</td></tr>
<tr>
<td>0</td><td>1</td><td>1</td></tr>
<tr>
<td>1</td><td>0</td><td>1</td></tr>
<tr>
<td>1</td><td>1</td><td>0</td></tr>
</tbody>
</table>
</div><p>Now that we have chosen a circuit, or DUT - Device Under Test (Industry jargon 101). It's time we write the code for the same using Verilog.</p>
<pre><code class="lang-plaintext">module xor_gate(input wire a,
input wire b,
output wire y
);

assign y = a^b;
endmodule
</code></pre>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> cocotb
<span class="hljs-keyword">from</span> cocotb.triggers <span class="hljs-keyword">import</span> Timer, RisingEdge

<span class="hljs-meta">@cocotb.test()</span>
<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">test_xor</span>(<span class="hljs-params">dut</span>):</span>
    a = (<span class="hljs-number">0</span>,<span class="hljs-number">0</span>,<span class="hljs-number">1</span>,<span class="hljs-number">1</span>)
    b = (<span class="hljs-number">0</span>,<span class="hljs-number">1</span>,<span class="hljs-number">0</span>,<span class="hljs-number">1</span>)
    y = (<span class="hljs-number">0</span>,<span class="hljs-number">1</span>,<span class="hljs-number">1</span>,<span class="hljs-number">0</span>)

    <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(<span class="hljs-number">4</span>):
        dut.a.value = a[i]
        dut.b.value = b[i]
        <span class="hljs-keyword">await</span> Timer(<span class="hljs-number">1</span>, <span class="hljs-string">'ns'</span>)
        <span class="hljs-keyword">assert</span> dut.y.value == y[i], <span class="hljs-string">f"Error at iteration <span class="hljs-subst">{i}</span>"</span>
</code></pre>
<p>In the python file we have basically defined the inputs that we will give to the DUT and the outputs that we expect.</p>
<pre><code class="lang-makefile"><span class="hljs-comment"># Makefile</span>

TOPLEVEL_LANG = verilog
VERILOG_SOURCES = <span class="hljs-variable">$(<span class="hljs-built_in">shell</span> pwd)</span>/../HDL/xor_gate.v
TOPLEVEL = xor_gate
MODULE = test_xor 

<span class="hljs-keyword">include</span> <span class="hljs-variable">$(<span class="hljs-built_in">shell</span> cocotb-config --makefiles)</span>/Makefile.sim
</code></pre>
<p>And Voila!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1711393572609/179fc4f2-7bf0-4cfc-9139-3ebb906d2721.png" alt class="image--center mx-auto" /></p>
<p>We did get a pass, but this is boring. I want to look at waveforms! To that end we will create a wrapper that dumps the waveform and calls our module. I could not get these two work in two separate files so I ended up pasting them in the same file.</p>
<pre><code class="lang-plaintext">module xor_gate(input wire a,
input wire b,
output wire y
);

assign y = a^b;
endmodule

module xor_wrapper(input wire a,
input wire b,
output wire y
);

xor_gate xor_1 (.a(a), .b(b), .y(y));

initial begin
    $dumpfile("waves.vcd");
    $dumpvars;
end
endmodule
</code></pre>
<p>This dumps out a waves.vcd file that you can view with GTKWave.</p>
<pre><code class="lang-bash">gtkwave waves.vcd
</code></pre>
<p>Lo and behold! Waveforms!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1711396282530/fb4ad622-ba6f-47a3-90f5-a5082125a522.png" alt class="image--center mx-auto" /></p>
]]></description><link>https://blog.mixedsignal.tech/more-about-design-verification</link><guid isPermaLink="true">https://blog.mixedsignal.tech/more-about-design-verification</guid><category><![CDATA[Python]]></category><category><![CDATA[verification]]></category><category><![CDATA[VLSI circuit design]]></category><dc:creator><![CDATA[Gursimran Singh]]></dc:creator></item><item><title><![CDATA[Getting started with Open Source Design Verification with Icarus Verilog and cocotb.]]></title><description><![CDATA[<p>As someone who was always more interested in the analog side of things, I never bothered to learn anything more than basic digital concepts. I joined Texas Instruments in a team that did Mixed-Signal ICs. As my exposure grew, I was intrigued by the world of Mixed Signal IC design and you can't really do Mixed Signal ICs without digital.</p>
<p>As I delved deeper into the world of digital, learning a Hardware Description Language became imperative, I had never bothered to learn more that basic VHDL during my undergrad and i found System Verilog counter intuitive. I had a good hold over python and while I am all for learning new things, I wanted to get some results quickly to motivate me to immerse myself in this pursuit.</p>
<p>The best thing for a beginner would probably be to go to a website like <a target="_blank" href="https://www.edaplayground.com/">EDAplayground</a>. But I am a huge fan of running things on my local machine so that is what we will do here.</p>
<p>The first couple of things that I needed to install were Python and Icarus Verilog. Apart from this I also setup a virtual environment.</p>
<pre><code class="lang-bash">sudo apt-get install make python3 python3-pip
sudo apt install iverilog
python3 -m venv myenv
</code></pre>
<p>Then I simply activated the environment and started installing cocotb and it's dependancies.</p>
<pre><code class="lang-bash"><span class="hljs-built_in">source</span> myenv/bin/activate
pip3 install pytest cocotb cocotb-bus cocotb-coverage
</code></pre>
<p>The next step is to try the sample code from <a target="_blank" href="https://github.com/cocotb/cocotb">cocotb GitHUb repo</a> to test a D Flip Flop. We create two files, dff.sv and test_dff.py</p>
<pre><code class="lang-plaintext">// dff.sv

`timescale 1us/1ns

module dff (
    output logic q,
    input logic clk, d
);

always @(posedge clk) begin
    q &lt;= d;
end

endmodule
</code></pre>
<pre><code class="lang-python"><span class="hljs-comment"># test_dff.py</span>

<span class="hljs-keyword">import</span> random

<span class="hljs-keyword">import</span> cocotb
<span class="hljs-keyword">from</span> cocotb.clock <span class="hljs-keyword">import</span> Clock
<span class="hljs-keyword">from</span> cocotb.triggers <span class="hljs-keyword">import</span> RisingEdge
<span class="hljs-keyword">from</span> cocotb.types <span class="hljs-keyword">import</span> LogicArray

<span class="hljs-meta">@cocotb.test()</span>
<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">dff_simple_test</span>(<span class="hljs-params">dut</span>):</span>
    <span class="hljs-string">"""Test that d propagates to q"""</span>

    <span class="hljs-comment"># Assert initial output is unknown</span>
    <span class="hljs-keyword">assert</span> LogicArray(dut.q.value) == LogicArray(<span class="hljs-string">"X"</span>)
    <span class="hljs-comment"># Set initial input value to prevent it from floating</span>
    dut.d.value = <span class="hljs-number">0</span>

    clock = Clock(dut.clk, <span class="hljs-number">10</span>, units=<span class="hljs-string">"us"</span>)  <span class="hljs-comment"># Create a 10us period clock on port clk</span>
    <span class="hljs-comment"># Start the clock. Start it low to avoid issues on the first RisingEdge</span>
    cocotb.start_soon(clock.start(start_high=<span class="hljs-literal">False</span>))

    <span class="hljs-comment"># Synchronize with the clock. This will regisiter the initial `d` value</span>
    <span class="hljs-keyword">await</span> RisingEdge(dut.clk)
    expected_val = <span class="hljs-number">0</span>  <span class="hljs-comment"># Matches initial input value</span>
    <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(<span class="hljs-number">10</span>):
        val = random.randint(<span class="hljs-number">0</span>, <span class="hljs-number">1</span>)
        dut.d.value = val  <span class="hljs-comment"># Assign the random value val to the input port d</span>
        <span class="hljs-keyword">await</span> RisingEdge(dut.clk)
        <span class="hljs-keyword">assert</span> dut.q.value == expected_val, <span class="hljs-string">f"output q was incorrect on the <span class="hljs-subst">{i}</span>th cycle"</span>
        expected_val = val <span class="hljs-comment"># Save random value for next RisingEdge</span>

    <span class="hljs-comment"># Check the final input on the next clock</span>
    <span class="hljs-keyword">await</span> RisingEdge(dut.clk)
    <span class="hljs-keyword">assert</span> dut.q.value == expected_val, <span class="hljs-string">"output q was incorrect on the last cycle"</span>
</code></pre>
<p>We also need a makefile to set the simulator for the HDL file.</p>
<pre><code class="lang-makefile"><span class="hljs-comment"># Makefile</span>

TOPLEVEL_LANG = verilog
VERILOG_SOURCES = <span class="hljs-variable">$(<span class="hljs-built_in">shell</span> pwd)</span>/dff.sv
TOPLEVEL = dff
MODULE = test_dff

<span class="hljs-keyword">include</span> <span class="hljs-variable">$(<span class="hljs-built_in">shell</span> cocotb-config --makefiles)</span>/Makefile.sim
</code></pre>
<p>The setup is now complete, we execute the simulation with Icarus Verilog</p>
<pre><code class="lang-makefile">make SIM=icarus
</code></pre>
<p>If all is as expected, this is what you ought to see after execution.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1710068172131/c4234921-934a-4a9c-993e-b02cddfc527a.png" alt class="image--center mx-auto" /></p>
<p>I'm going to try to understand more about cocotb and verification and the next blog would probably have more details.</p>
]]></description><link>https://blog.mixedsignal.tech/getting-started-with-open-source-design-verification-with-icarus-verilog-and-cocotb</link><guid isPermaLink="true">https://blog.mixedsignal.tech/getting-started-with-open-source-design-verification-with-icarus-verilog-and-cocotb</guid><category><![CDATA[verilog]]></category><category><![CDATA[Python]]></category><category><![CDATA[verification]]></category><category><![CDATA[VLSI circuit design]]></category><dc:creator><![CDATA[Gursimran Singh]]></dc:creator></item><item><title><![CDATA[A naive approach to Digital Filters.]]></title><description><![CDATA[<p>Filters are important, they make water safe to drink. But if you're majoring in Electrical/Electronics engineering, they probably mean something different to you. For starters let us think of our filter as a black box with one input and one output. You input something and something comes out. There are an infinite number of things that could happen inside that box.</p>
<p>I recommend that the reader be familiar with extremely basic aspects of signal processing, like the delta function and the Fourier transform among other things for this blog to truly make sense.</p>
<h1 id="heading-basics">Basics</h1>
<p>To somewhat lessen the scope of what can happen inside that black box, we introduce two major constraints,</p>
<ol>
<li><p>Linearity - "The sum of outputs is equal to the output of sums"</p>
</li>
<li><p>Time Invariance - This essentially means that the performance of our black box does not depend explicitly on time.</p>
</li>
</ol>
<p>Once these two conditions are satisfied, we can conveniently refer to our black box as an LTI system, LTI being Linear, Time-Invariant.</p>
<p>$$Impulse \hspace{0.25cm} response \hspace{0.25cm} of \hspace{0.25cm} a \hspace{0.25cm} filter \hspace{0.25cm} : \hspace{0.5cm} h[n]$$</p><p>I often heard my professors say, "A fundamental result is that the impulse response characterizes a filter". Turns out that the impulse response of a filter is nothing but the output of the filter when the input is a delta function.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1641443679132/BOeOk3Tqc.png" alt="delta.png" /></p>
<p>But why is the impulse response so important - once you have the impulse response of a filter, you simply convolve the impulse response with the input of your filter and you get the output. Convolve once again is just a fancy name given to a particular summation because it is used so often in signal processing.</p>
<p>Convolution is represented by the asterisk(*) operator which is why most signal processing texts simply do not use it to represent multiplication.</p>
<p>$$y[n] = x[n]*h[n]$$</p><p>Here, y[n] is the output of the filter, and x[n] is the input to the filter.</p>
<h1 id="heading-analysis">Analysis</h1>
<p>If you're familiar with a little bit of signal processing, you probably know about the time and frequency domains. To classify filters, we first take a peek at the impulse response of a filter from the time domain :</p>
<ol>
<li><p>FIR/ Finite Impulse Response: the impulse response is finite in nature</p>
</li>
<li><p>IIR/ Infinite Impulse Response: duh!</p>
</li>
</ol>
<p>Since we covered time, it only makes sense to see what the frequency domain has to offer: Frequency response of a filter is determined by the Discrete-Time Fourier Transform (DTFT) of its Impulse Response, as with any complex quantity once we obtain the frequency response we divide it into a magnitude and a phase term. The magnitude of the frequency response determines if the filter is going to be low-pass, high-pass, or band-pass. A low-pass filter allows low frequencies to pass and similarly for high-pass and band-pass.</p>
<p><em>A neat observation is that if the phase term of the frequency response is proportional to the frequency or in other words is a "pure complex exponential", the filter simply adds a delay to our signal.</em></p>
<p>Ideally, you would want your filter to have zero phase, so as to not add any delay to the output of the filter. You would also want to infinitely attenuate all frequencies that are outside the passband so that none of them show up in the output. But when we take a look at the impulse response of an ideal filter, the impulse response is not absolutely summable and thus isn't BIBO stable. BIBO stands for Bounded Input Bounded Output, to know more about the stability of a filter, check out this <a target="_blank" href="https://view.officeapps.live.com/op/view.aspx?src=http%3A%2F%2Fusers.ece.utexas.edu%2F~adnan%2Fcomm%2Fstability.doc%23%3A~%3Atext%3DThe%2520%25E2%2580%259Cabsolutely%2520summable%25E2%2580%259D%2520refers%2520to%2Cinput%2520x%2520and%2520output%2520y.&amp;wdOrigin=BROWSELINK">link.</a></p>
<h1 id="heading-windows">Windows</h1>
<p>The impulse response of an ideal filter extends infinitely in either direction on the X-axis, logic dictates that since the infinite extension of the impulse response is the root cause of our inability to design an ideal digital filter, we truncate it.</p>
<p>This is where <em>windows</em> come in. A window can be thought of as a sequence that we multiply our impulse response with to truncate it</p>
<p>For simplicity, we can assume our window to be a rectangular window, which is defined as :</p>
<p>$$\begin{align} w[n] &amp; = 1 \hspace{0.5cm} for \hspace{0.5cm}|n|&lt;=N \\ &amp; = 0 \hspace{0.5cm} otherwise \\ \end{align}$$</p><p>Our new impulse response becomes</p>
<p>$$\hat{h} [n] = h[n]w[n]$$</p><p><em>Note: there are many other window functions out there namely, Triangular, Hamming, Hanning, and so on.</em></p>
<h1 id="heading-the-z-transform">The Z Transform</h1>
<p>For designing filters, we are interested in the H[e^j], the Fourier transform of the impulse response h[n]. So we use something known as the Z transform. We already know $$ y[n] = x[n]*h[n] $$ We take the z transform on both sides. A little mathematical background about the Z transform can be found <a target="_blank" href="https://view.officeapps.live.com/op/view.aspx?src=http%3A%2F%2Fusers.ece.utexas.edu%2F~adnan%2Fcomm%2Fstability.doc%23%3A~%3Atext%3DThe%2520%25E2%2580%259Cabsolutely%2520summable%25E2%2580%259D%2520refers%2520to%2Cinput%2520x%2520and%2520output%2520y.&amp;wdOrigin=BROWSELINK">here.</a></p>
<p>We get</p>
<p>$$\begin{align} Z(y[n]) = Z(h[n]*x[n])\\ Y(z) = H(z)X(z)\\ H(z) = Y(z)/X(z) \end{align}$$</p><p>H(z) is known as the transfer function and when we input $$ z = e^{j} $$ in the transfer function. We get the frequency response of the filter.</p>
<p>We can consider H(z) to be a ratio of two polynomials which explains why we cannot have sharp transition bands as it would introduce discontinuity and polynomials are continuous by definition.</p>
<h1 id="heading-filter-specification">Filter Specification</h1>
<p>Every time we would go about designing a filter we would essentially have 2 constraints</p>
<ol>
<li><p>Frequency Response - Which frequencies do we want/ don't want.</p>
</li>
<li><p>Phase - No phase, linear phase, etc</p>
</li>
</ol>
<p>And practically we also have a third constrain which is the computation power available to us.</p>
<p>The image shows the ideal frequency response of a low-pass filter.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1641538837248/k9jNDKC-W.png" alt="image.png" /></p>
<p>Since our transfer function is a polynomial we can't have the immediate transition from passband to stopband.</p>
<p>A practical low pass filter has a frequency response that looks like this</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1641538883066/HX4TlaYrG.png" alt="image.png" /></p>
<p>Both images have been taken from <a target="_blank" href="https://www.dspguide.com/">this book.</a></p>
<p>The ripples in the passband and the width of the transition band can both be minimized as we increase filter order. But increase in filter order can prove to be computationally expensive, which is why we have the third constraint - computational power.</p>
<h1 id="heading-filter-design">Filter Design</h1>
<p>Remember when I said that the H(z) is equal to a polynomial; designing a filter involves calculating the various coefficients of the said polynomial, but thankfully due to various numerical packages available in MATLAB and Python. We never really need to do that. In fact, for the most part, you'll find yourself using a trial and error approach - you'll use some premade filter and alter the parameters till it satisfies your requirements.</p>
<p>That's it for now folks. Do let me know if I've published some wrong information, or you have some suggestions.</p>
]]></description><link>https://blog.mixedsignal.tech/a-naive-approach-to-digital-filters</link><guid isPermaLink="true">https://blog.mixedsignal.tech/a-naive-approach-to-digital-filters</guid><category><![CDATA[Python]]></category><dc:creator><![CDATA[Gursimran Singh]]></dc:creator></item></channel></rss>