<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"><title>Three-Speed Logic</title><link href="http://threespeedlogic.com/" rel="alternate"></link><link href="http://threespeedlogic.com/feeds/all.atom.xml" rel="self"></link><id>http://threespeedlogic.com/</id><updated>2020-06-25T00:00:00-07:00</updated><entry><title>Running Vivado in an LXC Container</title><link href="http://threespeedlogic.com/running-vivado-on-lxc.html" rel="alternate"></link><published>2020-06-25T00:00:00-07:00</published><updated>2020-06-25T00:00:00-07:00</updated><author><name>Graeme Smecher</name></author><id>tag:threespeedlogic.com,2020-06-25:/running-vivado-on-lxc.html</id><summary type="html">&lt;p class="first last"&gt;Running Vivado in an LXC container for fun and profit&lt;/p&gt;
</summary><content type="html">&lt;div class="contents topic" id="table-of-contents"&gt;
&lt;p class="topic-title"&gt;Table of Contents&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference internal" href="#summary" id="id3"&gt;Summary&lt;/a&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class="reference internal" href="#the-problem" id="id4"&gt;The Problem&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#the-solution" id="id5"&gt;The Solution&lt;/a&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class="reference internal" href="#installing-and-configuring-lxc-on-the-host" id="id6"&gt;Installing and Configuring LXC on the Host&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#creating-the-container" id="id7"&gt;Creating the Container&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#configuring-the-container" id="id8"&gt;Configuring the Container&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#installation-and-licensing" id="id9"&gt;Installation and Licensing&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#questions-and-answers" id="id10"&gt;Questions and Answers&lt;/a&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class="reference internal" href="#how-do-vivado-licenses-work-with-lxc" id="id11"&gt;How do Vivado licenses work with LXC?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#why-not-a-virtual-machine-vm" id="id12"&gt;Why Not a Virtual Machine (VM)?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#what-s-a-container" id="id13"&gt;What's a Container?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#what-s-lxc" id="id14"&gt;What's LXC?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#why-not-docker" id="id15"&gt;Why Not Docker?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#what-about-multiple-users-non-sudo-lxc" id="id16"&gt;What about multiple users / non-sudo LXC?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#surely-there-s-a-catch" id="id17"&gt;Surely there's a Catch?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="summary"&gt;
&lt;h2&gt;&lt;a class="toc-backref" href="#id3"&gt;Summary&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Don't run Vivado on your host OS.
Run it in an LXC container instead.
Here's why and how.&lt;/p&gt;
&lt;div class="section" id="the-problem"&gt;
&lt;h3&gt;&lt;a class="toc-backref" href="#id4"&gt;The Problem&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Each Vivado release is supported on a limited set of Linux distributions and releases.
While Xilinx documents this well in Vivado's release notes, and attempts to maintain compatibility, newer Vivado releases require newer (but not quite the newest) OSes.&lt;/p&gt;
&lt;p&gt;When you need to run multiple Vivado versions, you can end up gridlocked, unable or unwilling to upgrade or maintain your PC.
For example:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;You cannot, with a single officially-supported distribution and release, run both new and old versions of Vivado.
For example, Vivado &lt;a class="reference external" href="https://www.xilinx.com/support/documentation/sw_manuals/xilinx2020_1/ug973-vivado-release-notes-install-license.pdf"&gt;2020.1&lt;/a&gt; and Vivado &lt;a class="reference external" href="https://www.xilinx.com/support/documentation/sw_manuals/xilinx2016_1/ug973-vivado-release-notes-install-license.pdf"&gt;2016.1&lt;/a&gt; are not both supported on any single version of any Linux distribution.&lt;/li&gt;
&lt;li&gt;&amp;quot;Rolling&amp;quot; changes to many Linux distributions, even within a single version, can also break Vivado.
This is a disincentive to regular OS maintainance and can have security implications.&lt;/li&gt;
&lt;li&gt;While you can often run Vivado outside the officially-supported distribution list, it does not always work.
Sometimes the problems are easily fixed (or google-able).
Sometimes you will be the first to stumble across an obscure segfault.
Xilinx support will often (and understandably) refuse to offer support in this scenario.&lt;/li&gt;
&lt;li&gt;Many other software packages (TI's Code Composer Studio; Microsemi's Libero; MATLAB) also impose restrictions on OS releases.
Managing to find a single OS that supports all your software becomes more unlikely the more packages impose these limitations.&lt;/li&gt;
&lt;li&gt;If upgrading Vivado requires you to upgrade your OS, you will defer upgrades until you absolutely need them.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is no way to live.
Besides, Debian isn't on Xilinx's approved list, and who wants to run a host OS that isn't Debian?&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="the-solution"&gt;
&lt;h3&gt;&lt;a class="toc-backref" href="#id5"&gt;The Solution&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;By running Vivado within an LXC container, we can separate the OS &lt;em&gt;we&lt;/em&gt; run (the &amp;quot;host&amp;quot; OS) from the OS Vivado &lt;em&gt;perceives&lt;/em&gt; (the &amp;quot;guest&amp;quot;).
By adding an extra OS layer, we are free to run multiple different guests for different versions of Vivado, and upgrade the host without worrying about breaking something obscure.&lt;/p&gt;
&lt;p&gt;The following instructions assume the following:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Host: Debian Testing, with full (sudo) access.&lt;/li&gt;
&lt;li&gt;Guest: Ubuntu 18.04.4 (bionic)&lt;/li&gt;
&lt;li&gt;Vivado: 2020.1&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I have used this recipe for several Vivado and Ubuntu releases, on the same Debian Testing host.&lt;/p&gt;
&lt;p&gt;These LXC directions are cribbed from the Debian wiki (&lt;a class="reference external" href="https://wiki.debian.org/LXC"&gt;https://wiki.debian.org/LXC&lt;/a&gt;).
Please go there for fuller, and possibly better maintained, guidance.&lt;/p&gt;
&lt;div class="section" id="installing-and-configuring-lxc-on-the-host"&gt;
&lt;h4&gt;&lt;a class="toc-backref" href="#id6"&gt;Installing and Configuring LXC on the Host&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Install the necessary packages:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ sudo apt-get install lxc libvirt-clients libvirt0 libpam-cgfs bridge-utils uidmap
&lt;/pre&gt;
&lt;p&gt;We will follow the &amp;quot;simple bridge&amp;quot; (lxc-net) version of the instructions.
Create the file &lt;code&gt;/etc/default/lxc-net&lt;/code&gt; with the following contents:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
USE_LXC_BRIDGE=&amp;quot;true&amp;quot;
LXC_BRIDGE=&amp;quot;lxcbr0&amp;quot;
LXC_ADDR=&amp;quot;10.0.3.1&amp;quot;
LXC_NETMASK=&amp;quot;255.255.255.0&amp;quot;
LXC_NETWORK=&amp;quot;10.0.3.0/24&amp;quot;
LXC_DHCP_RANGE=&amp;quot;10.0.3.2,10.0.3.254&amp;quot;
LXC_DHCP_MAX=&amp;quot;253&amp;quot;
LXC_DHCP_CONFILE=&amp;quot;&amp;quot;
LXC_DOMAIN=&amp;quot;&amp;quot;
&lt;/pre&gt;
&lt;p&gt;Now enable and start &lt;code&gt;lxc-net&lt;/code&gt;:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
host$ sudo systemctl enable lxc-net
host$ sudo systemctl start lxc-net
&lt;/pre&gt;
&lt;p&gt;At this point I had to reboot my system to see the network device &lt;cite&gt;lxcbr0&lt;/cite&gt; appear:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
host$ sudo reboot
[...]
host$ sudo ifconfig lxcbr0
lxcbr0: flags=4099&amp;lt;UP,BROADCAST,MULTICAST&amp;gt; mtu 1500
        inet 10.0.3.1 netmask 255.255.255.0 broadcast 0.0.0.0
[...]
&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="creating-the-container"&gt;
&lt;h4&gt;&lt;a class="toc-backref" href="#id7"&gt;Creating the Container&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Create and start a container named &lt;cite&gt;vivado2020_1&lt;/cite&gt; as follows:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
host$ sudo lxc-create -n vivado2020_1 -t ubuntu -- -r bionic
&lt;/pre&gt;
&lt;p&gt;Do not start the container yet (we'll do that below).&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="configuring-the-container"&gt;
&lt;h4&gt;&lt;a class="toc-backref" href="#id8"&gt;Configuring the Container&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Now, in the host, edit the container configuration (&lt;cite&gt;/var/lib/lxc/vivado2020_1/config&lt;/cite&gt;) and add the following lines:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
# Network configuration
lxc.net.0.type = veth
lxc.net.0.flags = up
lxc.net.0.link = lxcbr0
lxc.net.0.hwaddr = aa:bb:cc:dd:ee:ff

# Xilinx
lxc.mount.entry=/home/your_username /var/lib/lxc/vivado2020_1/rootfs/home/your_username none bind 0 0
lxc.mount.entry=/opt/xilinx /var/lib/lxc/vivado2020_1/rootfs/opt/xilinx none bind 0 0

# Automatically start this container
lxc.start.auto = 1
&lt;/pre&gt;
&lt;p&gt;You will have to modify &lt;em&gt;three&lt;/em&gt; things here:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;The &amp;quot;hwaddr&amp;quot; should correspond to an arbitrary MAC address with a valid Xilinx license.&lt;/li&gt;
&lt;li&gt;&lt;cite&gt;your_username&lt;/cite&gt; should be changed to match your setup&lt;/li&gt;
&lt;li&gt;&lt;cite&gt;/opt/xilinx&lt;/cite&gt; should be altered to match your host's Xilinx installation (&lt;cite&gt;/opt/Xilinx&lt;/cite&gt; is default, I think.)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You will have to create the bind-mount directories on your host, matching your alterations above:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
host$ sudo mkdir -p /var/lib/lxc/vivado2020_1/rootfs/home/your_username
host$ sudo mkdir -p /var/lib/lxc/vivado2020_1/rootfs/opt/xilinx
&lt;/pre&gt;
&lt;p&gt;Now, start the container, attach to it, and configure it as follows:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
host$ sudo lxc-start -n vivado2020_1
host$ sudo lxc-attach -n vivado2020_1
&lt;/pre&gt;
&lt;p&gt;This last command will bring up a root prompt inside the container.
Install a few basic packages:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
guest# apt-get update
guest# apt-get install avahi-daemon openssh-server xutils x11-apps xauth
&lt;/pre&gt;
&lt;p&gt;You will also want to modify the &lt;cite&gt;ubuntu&lt;/cite&gt; user to match your UID and GID on the host, and set its password:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
guest# usermod -u 1000 -g 1000 -d /home/your_username -l your_username ubuntu
guest# passwd your_username
&lt;/pre&gt;
&lt;p&gt;...where the UID 1000 and GID 1000, here, should be altered to match your UID and GID on the host.
You can find these by running &lt;cite&gt;id -u&lt;/cite&gt; and &lt;cite&gt;id -g&lt;/cite&gt; on the host.&lt;/p&gt;
&lt;p&gt;You can now &lt;cite&gt;exit&lt;/cite&gt; out of the root session and restart the container:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
host$ sudo lxc-stop -n vivado2020_1
host$ sudo lxc-start -n vivado2020_1
&lt;/pre&gt;
&lt;p&gt;You now have a user in the container that matches your user on the host.
To avoid entering your password each time, use the &lt;cite&gt;ssh-copy-id&lt;/cite&gt; script:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
host$ ssh-copy-id vivado2020_1.local
&lt;/pre&gt;
&lt;p&gt;If these steps worked, you can now &amp;quot;ssh&amp;quot; into the machine and run the all-important &lt;cite&gt;xeyes&lt;/cite&gt; test:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
host$ ssh -XC vivado2020_1.local xeyes
&lt;/pre&gt;
&lt;p&gt;If the eyes show up, congratulations!
You are able to connect to the container and forward X11 apps, which is how you'll be using Vivado.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="installation-and-licensing"&gt;
&lt;h4&gt;&lt;a class="toc-backref" href="#id9"&gt;Installation and Licensing&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;If your host already has Vivado installed, it is also installed on your client.
(That's what the &lt;cite&gt;lxc.mount.entry&lt;/cite&gt; line above accomplished.)&lt;/p&gt;
&lt;p&gt;If not, you can now install it inside your guest (but note that you will have to grant write permission on the &lt;em&gt;host's&lt;/em&gt; &lt;cite&gt;/opt/xilinx&lt;/cite&gt; to the user within your guest!)
Your environment inside the LXC environment should be similar to the environment outside.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="questions-and-answers"&gt;
&lt;h2&gt;&lt;a class="toc-backref" href="#id10"&gt;Questions and Answers&lt;/a&gt;&lt;/h2&gt;
&lt;div class="section" id="how-do-vivado-licenses-work-with-lxc"&gt;
&lt;h3&gt;&lt;a class="toc-backref" href="#id11"&gt;How do Vivado licenses work with LXC?&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This depends on you.&lt;/p&gt;
&lt;p&gt;Network licenses likely &amp;quot;just work&amp;quot; once you set up the server.&lt;/p&gt;
&lt;p&gt;My Vivado installations are licensed by Ethernet MAC address.
In this regime, the simplest (and most legitimate) way is to issue a separate license file for each guest.
You will need to assign randomly generated MAC addresses to your guests via the &lt;cite&gt;config&lt;/cite&gt; file you modified above.
(See the &lt;cite&gt;hwaddr&lt;/cite&gt; line.)&lt;/p&gt;
&lt;p&gt;If you are interested in re-using the same MAC-based license as your host uses (&lt;strong&gt;I am not advocating this!&lt;/strong&gt;), you should be able to create a dummy Ethernet interface in your guest with the same MAC address as your host's licensed Ethernet address.
Provided no traffic flows over this interface, the fact that we have two Ethernet adapters on the same PC with the same MAC address is not problematic.
While this is probably against Xilinx's terms of service, it's hard to imagine they would really have a problem with you running the software on the PC it's licensed with (albeit with an extra OS layer between the licensed MAC and Vivado.)&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="why-not-a-virtual-machine-vm"&gt;
&lt;h3&gt;&lt;a class="toc-backref" href="#id12"&gt;Why Not a Virtual Machine (VM)?&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Most FPGA designers will be familiar with Virtual Machines (VMs) like VirtualBox or VMWare.
These programs, with the help of OS- and processor-level features, emulate an entire PC and provide a well-isolated sandbox for you to install a &amp;quot;guest&amp;quot; OS on your PC.
This guest OS is completely separate from your host OS, which can run several guests at a time.&lt;/p&gt;
&lt;p&gt;You can install Vivado in a VM running an approved Linux distribution.
However, you shouldn't.
VMs generally require a fixed allocation of resources (RAM, disk, CPUs).
When you run Vivado, you typically want it to consume as much CPU and RAM as it needs, up to the limits imposed by your hardware.
Whenever your VM requires a static allocation, you are artificially hobbling the performance of both the host and guest.
Even if you don't run into artificial resource limits imposed by static allocations, a VM will perform worse due to the extra virtualization overhead over a container.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="what-s-a-container"&gt;
&lt;h3&gt;&lt;a class="toc-backref" href="#id13"&gt;What's a Container?&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A container is like a VM, only less virtualized.
Where a VM host virtualizes the CPU and allows a guest to run its own OS, a container runs only a single kernel and virtualizes only the userspace environment.
The host and guest share kernel, and hence hardware, drivers, CPUs, and memory.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="what-s-lxc"&gt;
&lt;h3&gt;&lt;a class="toc-backref" href="#id14"&gt;What's LXC?&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a class="reference external" href="https://linuxcontainers.org"&gt;LXC&lt;/a&gt; is one of several container management packages commonly provided in Linux distributions.
Alternative container services include &lt;a class="reference external" href="https://linuxcontainers.org"&gt;LXD&lt;/a&gt; (a user-friendlier layer on LXC, but which is not packed for Debian) and Docker, which solves a slightly different problem.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="why-not-docker"&gt;
&lt;h3&gt;&lt;a class="toc-backref" href="#id15"&gt;Why Not Docker?&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a class="reference external" href="https://www.docker.com"&gt;Docker&lt;/a&gt;, like LXC, is a container management service.
However, Docker is intended to build short-lived, reproducible containers for non-interactive use.
Vivado is a pretty poor match for these environments because it is so big, and because reproducing an automated Xilinx installation is not easy.
Although you can find Docker instructions (Dockerfiles) for Vivado on-line, they are more of a hassle than the above procedure.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="what-about-multiple-users-non-sudo-lxc"&gt;
&lt;h3&gt;&lt;a class="toc-backref" href="#id16"&gt;What about multiple users / non-sudo LXC?&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Sorry, it's possible but it's not what I describe here.
I use this on my laptop and workstation, so I'm the only one driving.
(I am aware that the manual uid remapping is slightly cheesy!)&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="surely-there-s-a-catch"&gt;
&lt;h3&gt;&lt;a class="toc-backref" href="#id17"&gt;Surely there's a Catch?&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;It is possible for the host kernel (which, remember, is shared with your guest OS) to be incompatible with something in the guest's userspace or in Vivado.
For example, kernel-level security features might expose a latent bug or assumption in the guest OS that Vivado doesn't tickle when used in a non-containerized environment.
I have not surveyed past versions of Vivado carefully to check for bugs.
As with all free internet advice, you are welcome to apply for a refund.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
</content><category term="Vivado"></category><category term="Linux"></category><category term="LXC"></category></entry><entry><title>C/RTL Cosimulation with Vivado and Python</title><link href="http://threespeedlogic.com/vivado-cosimulation-with-xsi.html" rel="alternate"></link><published>2020-06-01T00:00:00-07:00</published><updated>2020-06-01T00:00:00-07:00</updated><author><name>Graeme Smecher</name></author><id>tag:threespeedlogic.com,2020-06-01:/vivado-cosimulation-with-xsi.html</id><summary type="html">&lt;p class="first last"&gt;A method to cosimulate C and RTL code under Python control&lt;/p&gt;
</summary><content type="html">&lt;div class="contents topic" id="table-of-contents"&gt;
&lt;p class="topic-title"&gt;Table of Contents&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference internal" href="#summary" id="id3"&gt;Summary&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#motivation" id="id4"&gt;Motivation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#demonstration" id="id5"&gt;Demonstration&lt;/a&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class="reference internal" href="#check-out-the-source-code" id="id6"&gt;Check Out the Source Code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#build-the-rtl" id="id7"&gt;Build the RTL&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#build-the-c-code" id="id8"&gt;Build the C++ Code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#execute-tests" id="id9"&gt;Execute Tests&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#conclusions" id="id10"&gt;Conclusions&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="summary"&gt;
&lt;h2&gt;&lt;a class="toc-backref" href="#id3"&gt;Summary&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Xilinx's xsim simulator (&lt;a class="reference external" href="https://www.xilinx.com/support/documentation/sw_manuals/xilinx2019_2/ug900-vivado-logic-simulation.pdf"&gt;UG900&lt;/a&gt;) includes the Xilinx Simulator Interface (XSI), a way to embed a RTL simulation kernel inside a C/C++ program.
This page further embeds XSI kernels within a Python session, creating a layered simulation environment where Python, C/C++, and RTL coexist.
Testbenches can be coded in a mixture of the three languages, removing the hard boundaries that surround an RTL-only testbench environment.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Warning&lt;/strong&gt;: As of Vivado 2020.2, fatal exceptions in RTL (VHDL: &lt;tt class="docutils literal"&gt;assert False severity failure&lt;/tt&gt;) currently leave the simulator kernel in a deeply inconsistent state.  Xilinx is aware and has promised a fix in an upcoming Vivado release. You will have to demote your exceptions to a non-fatal severity in the meantime.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="motivation"&gt;
&lt;h2&gt;&lt;a class="toc-backref" href="#id4"&gt;Motivation&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;RTL testbenches are a good way to verify low-level design elements, but RTL testbenches alone are not good enough.&lt;/p&gt;
&lt;p&gt;Most importantly, &lt;strong&gt;I want to test RTL using best-of-breed tools from the software world&lt;/strong&gt;.
I want to automate regression testing, launch tests quickly and in parallel, and automatically discover tests.
I want tests to be parameterized, randomized, and able to execute remotely without struggling to manage licensing limitations.&lt;/p&gt;
&lt;p&gt;Next, &lt;strong&gt;I want to verify a combination of C and RTL code&lt;/strong&gt;, where the interface between C and RTL is complex and malleable.
Driving a wedge between C code and RTL code so I can extract test vectors via file I/O feels like a monumental distraction.&lt;/p&gt;
&lt;p&gt;Also, &lt;strong&gt;I need to generate or post-process test data in Python.&lt;/strong&gt;
For signal-processing analysis, my go-to environment is Python/Scipy/Matplotlib.
For data analysis, there is nothing in C or RTL that offer the same broad reach and high productivity.
You can do this by running pre- and post-processing scripts, but it is brittle and frustrating for no justifiable reason.&lt;/p&gt;
&lt;p&gt;Yes, there's more: &lt;strong&gt;I want my test environment to resemble my deployment environment.&lt;/strong&gt;
My design is an amalgam of C and RTL when it's deployed; why should the testing environment be different?
(Here, ASIC designers will be tearing out their hair. It's OK, I understand.)
Combining C and RTL reduces the amount of hassle associated with testing, which allows me to focus on solving problems and not fighting tools.&lt;/p&gt;
&lt;p&gt;Finally: &lt;strong&gt;I need all of this to work with mixed languages (SystemVerilog/VHDL) and encrypted IP&lt;/strong&gt;.
This, unfortunately, shuts out all of the open-source simulators (Verilator, GHDL, CXXRTL) I would love to be supporting and using.
While the open-source tools are creeping closer to mixed-language simulation, it is difficult to see a (legal) path towards supporting encrypted IP in an open simulator.
Practically speaking, I'm stuck with either Xilinx's simulator (xsim), or very expensive commercial options.&lt;/p&gt;
&lt;p&gt;Compounding the issue further: many excellent test environments (&lt;a class="reference external" href="https://github.com/cocotb/cocotb"&gt;cocotb&lt;/a&gt;, &lt;a class="reference external" href="https://vunit.github.io/"&gt;VUnit&lt;/a&gt;, &lt;a class="reference external" href="https://github.com/UVVM/UVVM"&gt;UVVM&lt;/a&gt;) do not work with Xilinx's simulator.
As a result, my options for higher-level testing constructs focused on an RTL world dwindle from &amp;quot;frustrating&amp;quot; to &amp;quot;squalid&amp;quot;.
This is largely Xilinx's fault: although it is slowly improving, xsim's support for SystemVerilog and VHDL-2008 constructs lags other simulators &lt;a class="footnote-reference" href="#id2" id="id1"&gt;[1]&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="demonstration"&gt;
&lt;h2&gt;&lt;a class="toc-backref" href="#id5"&gt;Demonstration&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The following sections show a start-to-finish build, from checking out the source code to completing a test.&lt;/p&gt;
&lt;div class="section" id="check-out-the-source-code"&gt;
&lt;h3&gt;&lt;a class="toc-backref" href="#id6"&gt;Check Out the Source Code&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Source code is available at &lt;a class="reference external" href="https://github.com/gsmecher/pyxsi"&gt;https://github.com/gsmecher/pyxsi&lt;/a&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$ git clone https://github.com/gsmecher/pyxsi.git
Cloning into &lt;span class="s1"&gt;&amp;#39;pyxsi&amp;#39;&lt;/span&gt;...
remote: Enumerating objects: &lt;span class="m"&gt;14&lt;/span&gt;, &lt;span class="k"&gt;done&lt;/span&gt;.
remote: Counting objects: &lt;span class="m"&gt;100&lt;/span&gt;% &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="m"&gt;14&lt;/span&gt;/14&lt;span class="o"&gt;)&lt;/span&gt;, &lt;span class="k"&gt;done&lt;/span&gt;.
remote: Compressing objects: &lt;span class="m"&gt;100&lt;/span&gt;% &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="m"&gt;12&lt;/span&gt;/12&lt;span class="o"&gt;)&lt;/span&gt;, &lt;span class="k"&gt;done&lt;/span&gt;.
remote: Total &lt;span class="m"&gt;14&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;delta &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;, reused &lt;span class="m"&gt;14&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;delta &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;, pack-reused &lt;span class="m"&gt;0&lt;/span&gt;
Receiving objects: &lt;span class="m"&gt;100&lt;/span&gt;% &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="m"&gt;14&lt;/span&gt;/14&lt;span class="o"&gt;)&lt;/span&gt;, &lt;span class="m"&gt;6&lt;/span&gt;.72 KiB &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="m"&gt;6&lt;/span&gt;.72 MiB/s, &lt;span class="k"&gt;done&lt;/span&gt;.
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="build-the-rtl"&gt;
&lt;h3&gt;&lt;a class="toc-backref" href="#id7"&gt;Build the RTL&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Now set up Xilinx's environment variables and build the RTL into a simulation library:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$ &lt;span class="nb"&gt;cd&lt;/span&gt; pyxsi
pyxsi$ . /opt/xilinx/Vivado/2019.2/settings64.sh
pyxsi$ make rtl
xelab work.widget -prj rtl/widget.prj -debug all -dll -s widget
Vivado Simulator &lt;span class="m"&gt;2019&lt;/span&gt;.2
Copyright &lt;span class="m"&gt;1986&lt;/span&gt;-1999, &lt;span class="m"&gt;2001&lt;/span&gt;-2019 Xilinx, Inc. All Rights Reserved.
Running: /opt/xilinx/Vivado/2019.2/bin/unwrapped/lnx64.o/xelab work.widget -prj rtl/widget.prj -debug all -dll -s widget
Multi-threading is on. Using &lt;span class="m"&gt;2&lt;/span&gt; slave threads.
Determining compilation order of HDL files.
INFO: &lt;span class="o"&gt;[&lt;/span&gt;VRFC &lt;span class="m"&gt;10&lt;/span&gt;-163&lt;span class="o"&gt;]&lt;/span&gt; Analyzing VHDL file &lt;span class="s2"&gt;&amp;quot;/home/foo/bar/baz/pyxsi/rtl/widget.vhd&amp;quot;&lt;/span&gt; into library work
INFO: &lt;span class="o"&gt;[&lt;/span&gt;VRFC &lt;span class="m"&gt;10&lt;/span&gt;-3107&lt;span class="o"&gt;]&lt;/span&gt; analyzing entity &lt;span class="s1"&gt;&amp;#39;widget&amp;#39;&lt;/span&gt;
Starting static elaboration
Completed static elaboration
Starting simulation data flow analysis
Completed simulation data flow analysis
Time Resolution &lt;span class="k"&gt;for&lt;/span&gt; simulation is 1ps
Compiling package std.standard
Compiling package std.textio
Compiling package ieee.std_logic_1164
Compiling package ieee.numeric_std
Compiling architecture behav of entity work.widget
Built XSI simulation shared library xsim.dir/widget/xsimk.so
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="build-the-c-code"&gt;
&lt;h3&gt;&lt;a class="toc-backref" href="#id8"&gt;Build the C++ Code&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Now build the C++ code:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;pyxsi$ make
g++ -fPIC -std&lt;span class="o"&gt;=&lt;/span&gt;c++17 -I/usr/include/python3.8 -I/opt/xilinx/Vivado/2019.2/data/xsim/include -Isrc -c -o pybind.o src/pybind.cpp
g++ -fPIC -std&lt;span class="o"&gt;=&lt;/span&gt;c++17 -I/usr/include/python3.8 -I/opt/xilinx/Vivado/2019.2/data/xsim/include -Isrc -c -o xsi_loader.o src/xsi_loader.cpp
g++ -fPIC -std&lt;span class="o"&gt;=&lt;/span&gt;c++17 -I/usr/include/python3.8 -I/opt/xilinx/Vivado/2019.2/data/xsim/include -Isrc -shared -o pyxsi.so pybind.o xsi_loader.o -ldl
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="execute-tests"&gt;
&lt;h3&gt;&lt;a class="toc-backref" href="#id9"&gt;Execute Tests&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Finally, tests are discovered and executed using Python's &lt;a class="reference external" href="https://docs.pytest.org/en/latest/"&gt;pytest&lt;/a&gt; environment.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;pyxsi$ make &lt;span class="nb"&gt;test&lt;/span&gt;
&lt;span class="o"&gt;=============================&lt;/span&gt; &lt;span class="nb"&gt;test&lt;/span&gt; session &lt;span class="nv"&gt;starts&lt;/span&gt; &lt;span class="o"&gt;==============================&lt;/span&gt;
platform linux -- Python &lt;span class="m"&gt;3&lt;/span&gt;.8.3rc1, pytest-4.6.9, py-1.8.1, pluggy-0.13.0
rootdir: /home/foo/bar/baz/pyxsi
plugins: xdist-1.32.0, forked-1.1.3
collected &lt;span class="m"&gt;2&lt;/span&gt; items
&lt;span class="o"&gt;[&lt;/span&gt;...&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="o"&gt;===========================================&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt; passed in &lt;span class="m"&gt;7&lt;/span&gt;.16 &lt;span class="nv"&gt;seconds&lt;/span&gt; &lt;span class="o"&gt;===========================================&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="conclusions"&gt;
&lt;h2&gt;&lt;a class="toc-backref" href="#id10"&gt;Conclusions&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This is only a skeletal example, with just enough scaffolding to build on.&lt;/p&gt;
&lt;p&gt;Since this article was first published, I've extended my own experiments into a fully-fledged regression-testing environment.
It's perfect for signal-path environments.
If you're curious, &lt;a class="reference external" href="mailto:gsmecher&amp;#64;threespeedlogic.com"&gt;please ask&lt;/a&gt; for details.&lt;/p&gt;
&lt;table class="docutils footnote" frame="void" id="id2" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label" /&gt;&lt;col /&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;&lt;a class="fn-backref" href="#id1"&gt;[1]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;I use xsim because none of the open-source simulators can combine VHDL and Verilog, or simulate encrypted IP.
Commercial simulators don't make sense for a small instrumentation consultancy (mine, anyway).&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
</content><category term="Vivado"></category><category term="xsim"></category><category term="XSI"></category></entry><entry><title>XSim's New AXI Analyzer</title><link href="http://threespeedlogic.com/vivado-protocol-analysis.html" rel="alternate"></link><published>2019-12-05T00:00:00-08:00</published><updated>2019-12-05T00:00:00-08:00</updated><author><name>Graeme Smecher</name></author><id>tag:threespeedlogic.com,2019-12-05:/vivado-protocol-analysis.html</id><summary type="html">&lt;p class="first last"&gt;Xilinx's simulator can intelligently display AXI in block designs. We want that in RTL too.&lt;/p&gt;
</summary><content type="html">&lt;div class="contents topic" id="table-of-contents"&gt;
&lt;p class="topic-title"&gt;Table of Contents&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference internal" href="#motivation" id="id1"&gt;Motivation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#axi-analyzer-in-block-designs" id="id2"&gt;AXI Analyzer in Block Designs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#using-the-axi-analyzer-in-rtl-only-designs" id="id3"&gt;Using the AXI Analyzer in RTL-Only Designs&lt;/a&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class="reference internal" href="#design-heirarchy" id="id4"&gt;Design Heirarchy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#creating-the-protoinst-file" id="id5"&gt;Creating the Protoinst File&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#launching-the-simulator" id="id6"&gt;Launching the Simulator&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#fully-expanded-axi-analyzer" id="id7"&gt;Fully Expanded AXI Analyzer&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="motivation"&gt;
&lt;h2&gt;&lt;a class="toc-backref" href="#id1"&gt;Motivation&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you've developed AXI machinery in Vivado, you're likely familiar with
this:&lt;/p&gt;
&lt;a class="reference external image-reference" href="/images/vivado/protoinst/plain_axi4_lite.png"&gt;&lt;img alt="" class="align-center" src="/images/vivado/protoinst/plain_axi4_lite.png" /&gt;&lt;/a&gt;
&lt;div class="line-block"&gt;
&lt;div class="line"&gt;&lt;br /&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;This screenshot from Xilinx's built-in simulator (xsim) shows two AXI4-Lite
writes followed by a single read. It's functional but, for designs of any
complexity, it's tough to keep track of both the forest (the high-level
behaviour you're presumably debugging) and the trees (the nitty-gritty
associated with each AXI transaction).&lt;/p&gt;
&lt;p&gt;Sometimes I use markers and signal colors to make navigation easier, but these
are throwaway techniques that aren't useful for more than a single simulator
session at a time.&lt;/p&gt;
&lt;p&gt;I often wish for some easily available visual cues that support moving around
the simulation without losing focus on the problem I'm trying to solve.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="axi-analyzer-in-block-designs"&gt;
&lt;h2&gt;&lt;a class="toc-backref" href="#id2"&gt;AXI Analyzer in Block Designs&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;You may be surprised to hear that Vivado 2019.1 added something better.
From the &lt;a class="reference external" href="https://www.xilinx.com/products/design-tools/vivado/vivado-whats-new.html#2019_1"&gt;2019.1 release notes&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Vivado Simulator&lt;/strong&gt;&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&amp;quot;Mark Simulation&amp;quot; feature in block diagram to add AXI interfaces in waveform viewer directly&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;That's a little oblique. Since a picture speaks a thousand words:&lt;/p&gt;
&lt;a class="reference external image-reference" href="/images/vivado/protoinst/annotated_axi4_lite.png"&gt;&lt;img alt="" class="align-center" src="/images/vivado/protoinst/annotated_axi4_lite.png" /&gt;&lt;/a&gt;
&lt;div class="line-block"&gt;
&lt;div class="line"&gt;&lt;br /&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;That thing at the bottom is a &amp;quot;protocol analyzer&amp;quot;, and if you're doing your
development in a Block Design, you may have already stumbled across it.
Lucky you.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="using-the-axi-analyzer-in-rtl-only-designs"&gt;
&lt;h2&gt;&lt;a class="toc-backref" href="#id3"&gt;Using the AXI Analyzer in RTL-Only Designs&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For RTL designs, unfortunately, it's not so easy. It does not appear that the
Vivado machinery that infers AXI buses from port names and a few judicious
X_INTERFACE-style attributes (VHDL) or comments (Verilog) is hooked up here.&lt;/p&gt;
&lt;p&gt;Unofficially, here's how you can get this working in Vivado 2019.2.&lt;/p&gt;
&lt;div class="section" id="design-heirarchy"&gt;
&lt;h3&gt;&lt;a class="toc-backref" href="#id4"&gt;Design Heirarchy&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Because we need to name design units within the heirarchy, I've included a
screenshot showing the heirarchy itself.&lt;/p&gt;
&lt;img alt="" class="align-center" src="/images/vivado/protoinst/heirarchy.png" /&gt;
&lt;div class="line-block"&gt;
&lt;div class="line"&gt;&lt;br /&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;This is a perverse mixture of VHDL, SystemVerilog, and Xilinx cores.&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;The simulation top-level (top) is SystemVerilog (because I'm using the AXI
VIP, which relies on SystemVerilog mojo).&lt;/li&gt;
&lt;li&gt;My custom AXI4-Lite peripheral (axi_hw) is written in VHDL, since that's what
the majority of my designs use.&lt;/li&gt;
&lt;li&gt;For AXI stimulus, I'm using Xilinx's AXI VIP. (As an aside, the project
settings matter here: Vivado 2019.2 segfaults when generating the simulator
unless the VIP's generated RTL is in Verilog, and the project settings are
what determines this.)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Since the top-level SystemVerilog is relatively short, I've pasted it in
entirety here.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="no"&gt;`timescale&lt;/span&gt; &lt;span class="mh"&gt;1&lt;/span&gt;&lt;span class="n"&gt;ns&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mh"&gt;1&lt;/span&gt;&lt;span class="n"&gt;ps&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;axi_vip_pkg::*&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;axi_vip_0_pkg::*&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="n"&gt;top&lt;/span&gt; &lt;span class="p"&gt;#(&lt;/span&gt;
    &lt;span class="k"&gt;parameter&lt;/span&gt; &lt;span class="k"&gt;integer&lt;/span&gt; &lt;span class="no"&gt;C_AXI_ADDR_WIDTH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mh"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;parameter&lt;/span&gt; &lt;span class="k"&gt;integer&lt;/span&gt; &lt;span class="no"&gt;C_AXI_DATA_WIDTH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mh"&gt;32&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="k"&gt;logic&lt;/span&gt; &lt;span class="n"&gt;m_axi_aclk&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mh"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;m_axi_aresetn&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mh"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;logic&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mh"&gt;3&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="mh"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;led&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;logic&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;C_AXI_ADDR_WIDTH&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mh"&gt;1&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="mh"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;m_axi_awaddr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;m_axi_araddr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;logic&lt;/span&gt; &lt;span class="n"&gt;m_axi_awvalid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;m_axi_awready&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;m_axi_wvalid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;m_axi_wready&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;logic&lt;/span&gt; &lt;span class="n"&gt;m_axi_arvalid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;m_axi_arready&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;m_axi_rvalid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;m_axi_rready&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;logic&lt;/span&gt; &lt;span class="n"&gt;m_axi_bvalid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;m_axi_bready&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;logic&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;C_AXI_DATA_WIDTH&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mh"&gt;1&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="mh"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;m_axi_wdata&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;m_axi_rdata&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;logic&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;C_AXI_DATA_WIDTH&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mh"&gt;8&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mh"&gt;1&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="mh"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;m_axi_wstrb&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;logic&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mh"&gt;1&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="mh"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;m_axi_bresp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;m_axi_rresp&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;always&lt;/span&gt; &lt;span class="p"&gt;#&lt;/span&gt;&lt;span class="mh"&gt;5&lt;/span&gt;&lt;span class="n"&gt;ns&lt;/span&gt; &lt;span class="n"&gt;m_axi_aclk&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;m_axi_aclk&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;axi_hw&lt;/span&gt; &lt;span class="p"&gt;#(&lt;/span&gt;&lt;span class="no"&gt;C_AXI_ADDR_WIDTH&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;C_AXI_DATA_WIDTH&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;dut&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;s_axi_aclk&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m_axi_aclk&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;s_axi_aresetn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m_axi_aresetn&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;s_axi_awaddr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m_axi_awaddr&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;s_axi_awvalid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m_axi_awvalid&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;s_axi_awready&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m_axi_awready&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;s_axi_wdata&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m_axi_wdata&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;s_axi_wstrb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m_axi_wstrb&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;s_axi_wvalid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m_axi_wvalid&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;s_axi_wready&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m_axi_wready&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;s_axi_bresp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m_axi_bresp&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;s_axi_bvalid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m_axi_bvalid&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;s_axi_bready&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m_axi_bready&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;s_axi_araddr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m_axi_araddr&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;s_axi_arvalid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m_axi_arvalid&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;s_axi_arready&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m_axi_arready&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;s_axi_rdata&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m_axi_rdata&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;s_axi_rresp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m_axi_rresp&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;s_axi_rvalid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m_axi_rvalid&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;s_axi_rready&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m_axi_rready&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;led&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;led&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="n"&gt;axi_vip_0&lt;/span&gt; &lt;span class="n"&gt;vip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;aclk&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m_axi_aclk&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;aresetn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m_axi_aresetn&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;m_axi_awaddr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m_axi_awaddr&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;m_axi_awvalid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m_axi_awvalid&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;m_axi_awready&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m_axi_awready&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;m_axi_wdata&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m_axi_wdata&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;m_axi_wstrb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m_axi_wstrb&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;m_axi_wvalid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m_axi_wvalid&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;m_axi_wready&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m_axi_wready&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;m_axi_bresp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m_axi_bresp&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;m_axi_bvalid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m_axi_bvalid&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;m_axi_bready&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m_axi_bready&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;m_axi_araddr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m_axi_araddr&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;m_axi_arvalid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m_axi_arvalid&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;m_axi_arready&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m_axi_arready&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;m_axi_rdata&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m_axi_rdata&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;m_axi_rresp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m_axi_rresp&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;m_axi_rvalid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m_axi_rvalid&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;m_axi_rready&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m_axi_rready&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="cm"&gt;/* AXI VIP stimulus */&lt;/span&gt;
&lt;span class="n"&gt;axi_vip_0_mst_t&lt;/span&gt; &lt;span class="n"&gt;master_agent&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;logic&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mh"&gt;31&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="mh"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mh"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;xil_axi_resp_t&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;initial&lt;/span&gt; &lt;span class="k"&gt;begin&lt;/span&gt;
    &lt;span class="cm"&gt;/* Create an agent */&lt;/span&gt;
    &lt;span class="n"&gt;master_agent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;axi_vip_0_mst&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;vip&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;inst&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="no"&gt;IF&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;master_agent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_agent_tag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Master VIP&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;master_agent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start_master&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="cm"&gt;/* Remove reset */&lt;/span&gt;
    &lt;span class="p"&gt;#&lt;/span&gt;&lt;span class="mh"&gt;50&lt;/span&gt;&lt;span class="n"&gt;ns&lt;/span&gt; &lt;span class="n"&gt;m_axi_aresetn&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mh"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="cm"&gt;/* Poke LED bit 0 */&lt;/span&gt;
    &lt;span class="p"&gt;#&lt;/span&gt;&lt;span class="mh"&gt;20&lt;/span&gt;&lt;span class="n"&gt;ns&lt;/span&gt; &lt;span class="n"&gt;master_agent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="no"&gt;AXI4LITE_WRITE_BURST&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
             &lt;span class="mh"&gt;12&amp;#39;h000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mh"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mh"&gt;32&amp;#39;h1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="cm"&gt;/* Poke LED bit 1 */&lt;/span&gt;
    &lt;span class="p"&gt;#&lt;/span&gt;&lt;span class="mh"&gt;20&lt;/span&gt;&lt;span class="n"&gt;ns&lt;/span&gt; &lt;span class="n"&gt;master_agent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="no"&gt;AXI4LITE_WRITE_BURST&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
             &lt;span class="mh"&gt;12&amp;#39;h004&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mh"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mh"&gt;32&amp;#39;h1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Peek LED bit 0 */&lt;/span&gt;
    &lt;span class="p"&gt;#&lt;/span&gt;&lt;span class="mh"&gt;20&lt;/span&gt;&lt;span class="n"&gt;ns&lt;/span&gt; &lt;span class="n"&gt;master_agent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="no"&gt;AXI4LITE_READ_BURST&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
             &lt;span class="mh"&gt;12&amp;#39;h000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mh"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="p"&gt;#&lt;/span&gt;&lt;span class="mh"&gt;100&lt;/span&gt;&lt;span class="n"&gt;ns&lt;/span&gt;
    &lt;span class="nb"&gt;$finish&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;endmodule&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="creating-the-protoinst-file"&gt;
&lt;h3&gt;&lt;a class="toc-backref" href="#id5"&gt;Creating the Protoinst File&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;When using block designs, Vivado creates &lt;code&gt;.protoinst&lt;/code&gt; files to annotate
AXI buses. These files are passed to xsim in order to create protocol
analyzers.&lt;/p&gt;
&lt;p&gt;Xilinx is not yet ready to generate &lt;code&gt;protoinst&lt;/code&gt; files for RTL-only
designs, so we do it by hand:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;quot;version&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;1.0&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;quot;modules&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;quot;top&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
         &lt;span class="nt"&gt;&amp;quot;proto_instances&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;quot;/M_AXI&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
               &lt;span class="nt"&gt;&amp;quot;interface&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;xilinx.com:interface:aximm:1.0&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
               &lt;span class="nt"&gt;&amp;quot;ports&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                  &lt;span class="nt"&gt;&amp;quot;ACLK&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nt"&gt;&amp;quot;actual&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;m_axi_aclk&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
                  &lt;span class="nt"&gt;&amp;quot;ARADDR&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nt"&gt;&amp;quot;actual&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;m_axi_araddr&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
                  &lt;span class="nt"&gt;&amp;quot;ARESETN&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nt"&gt;&amp;quot;actual&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;m_axi_aresetn&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
                  &lt;span class="nt"&gt;&amp;quot;ARREADY&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nt"&gt;&amp;quot;actual&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;m_axi_arready&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
                  &lt;span class="nt"&gt;&amp;quot;ARVALID&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nt"&gt;&amp;quot;actual&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;m_axi_arvalid&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
                  &lt;span class="nt"&gt;&amp;quot;AWADDR&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nt"&gt;&amp;quot;actual&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;m_axi_awaddr&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
                  &lt;span class="nt"&gt;&amp;quot;AWREADY&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nt"&gt;&amp;quot;actual&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;m_axi_awready&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
                  &lt;span class="nt"&gt;&amp;quot;AWVALID&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nt"&gt;&amp;quot;actual&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;m_axi_awvalid&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
                  &lt;span class="nt"&gt;&amp;quot;BREADY&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nt"&gt;&amp;quot;actual&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;m_axi_bready&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
                  &lt;span class="nt"&gt;&amp;quot;BRESP&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nt"&gt;&amp;quot;actual&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;m_axi_bresp&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
                  &lt;span class="nt"&gt;&amp;quot;BVALID&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nt"&gt;&amp;quot;actual&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;m_axi_bvalid&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
                  &lt;span class="nt"&gt;&amp;quot;RDATA&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nt"&gt;&amp;quot;actual&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;m_axi_rdata&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
                  &lt;span class="nt"&gt;&amp;quot;RREADY&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nt"&gt;&amp;quot;actual&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;m_axi_rready&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
                  &lt;span class="nt"&gt;&amp;quot;RRESP&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nt"&gt;&amp;quot;actual&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;m_axi_rresp&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
                  &lt;span class="nt"&gt;&amp;quot;RVALID&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nt"&gt;&amp;quot;actual&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;m_axi_rvalid&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
                  &lt;span class="nt"&gt;&amp;quot;WDATA&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nt"&gt;&amp;quot;actual&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;m_axi_wdata&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
                  &lt;span class="nt"&gt;&amp;quot;WREADY&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nt"&gt;&amp;quot;actual&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;m_axi_wready&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
                  &lt;span class="nt"&gt;&amp;quot;WSTRB&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nt"&gt;&amp;quot;actual&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;m_axi_wstrb&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
                  &lt;span class="nt"&gt;&amp;quot;WVALID&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nt"&gt;&amp;quot;actual&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;m_axi_wvalid&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
               &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
         &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You will likely need to modify the instance name (&amp;quot;top&amp;quot;) and AXI signal names
(&amp;quot;m_axi_awaddr&amp;quot; etc.) to match your design.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="launching-the-simulator"&gt;
&lt;h3&gt;&lt;a class="toc-backref" href="#id6"&gt;Launching the Simulator&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Once your &lt;code&gt;.protoinst&lt;/code&gt; file matches your design, you need to pass it to
xsim. I find this most convenient to do on the command line, outside of Vivado.
The first step is to find your simulation directory:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
# from somewhere in the Vivado project directory:
$ find . -name simulate.sh
./my_design.sim/sim_1/behav/xsim/simulate.sh
$ cd my_design.sim/sim_1/behav/xsim
&lt;/pre&gt;
&lt;p&gt;This directory contains a &lt;code&gt;simulate.sh&lt;/code&gt; script generated by Vivado that
invokes xsim:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ tail -2 simulate.sh
xsim top_behav -key {Behavioral:sim_1:Functional:top} -tclbatch top.tcl -log simulate.log
&lt;/pre&gt;
&lt;p&gt;All we need to do is add the &amp;quot;-protoinst&amp;quot; option (pointing to our JSON file):&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ xsim top_behav -key {Behavioral:sim_1:Functional:top} \
        -tclbatch top.tcl -log simulate.log \
        -protoinst my_design.protoinst
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="fully-expanded-axi-analyzer"&gt;
&lt;h2&gt;&lt;a class="toc-backref" href="#id7"&gt;Fully Expanded AXI Analyzer&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;That's it! You should now be able to annotate AXI transactions in an RTL-only
design. I'll leave you with a fully expanded image of the AXI analyzer showing
what signals and derived information are visible.&lt;/p&gt;
&lt;a class="reference external image-reference" href="/images/vivado/protoinst/axi4_lite_fully_expanded.png"&gt;&lt;img alt="" class="align-center" src="/images/vivado/protoinst/axi4_lite_fully_expanded.png" /&gt;&lt;/a&gt;
&lt;div class="line-block"&gt;
&lt;div class="line"&gt;&lt;br /&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
</content><category term="Vivado"></category><category term="xsim"></category><category term="AXI"></category></entry><entry><title>Designing CIC Compensation Filters</title><link href="http://threespeedlogic.com/cic-compensation.html" rel="alternate"></link><published>2019-11-18T00:00:00-08:00</published><updated>2019-11-18T00:00:00-08:00</updated><author><name>Graeme Smecher</name></author><id>tag:threespeedlogic.com,2019-11-18:/cic-compensation.html</id><summary type="html">&lt;p class="first last"&gt;Designing CIC compensation filters without MATLAB&lt;/p&gt;
</summary><content type="html">&lt;p&gt;This page describes how to design CIC compensation filters using open-source
tools. Due to the use of newer algorithms, compensators designed using this
method should outperform MATLAB's built-in &amp;quot;ciccomp&amp;quot; filters.&lt;/p&gt;
&lt;div class="contents topic" id="table-of-contents"&gt;
&lt;p class="topic-title"&gt;Table of Contents&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference internal" href="#a-little-motivation" id="id9"&gt;A Little Motivation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#introducing-the-cic-filter" id="id10"&gt;Introducing the CIC Filter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#a-magic-trick-small-angle-approximation" id="id11"&gt;A Magic Trick: Small-Angle Approximation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#compensating-cic-filters" id="id12"&gt;Compensating CIC Filters&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#the-solution" id="id13"&gt;The Solution&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#references" id="id14"&gt;References&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="a-little-motivation"&gt;
&lt;h2&gt;&lt;a class="toc-backref" href="#id9"&gt;A Little Motivation&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Occasionally, DSP designers need to build decimators.&lt;/p&gt;
&lt;img alt="" class="align-center" src="/images/ciccomp/signal_path_unsolved.png" /&gt;
&lt;div class="line-block"&gt;
&lt;div class="line"&gt;&lt;br /&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Here, the goal is to remove high-frequency content from a sampled data source,
producing a new sequence of data samples at a lower sampling rate.&lt;/p&gt;
&lt;p&gt;From a theoretical perspective, the canonical approach to decimation is to use
a Finite Impulse Response (FIR) filter. FIR decimators are well-understood,
well-behaved, and approachable. FIR design is mature, and there exists a
canonical FIR design tool (the &lt;a class="citation-reference" href="#parks-mcclellan" id="id1"&gt;[Parks-McClellan]&lt;/a&gt; or Remez algorithm) that
makes it straightforward to turn a filter specification into a set of FIR
coefficients.  Implementations of this algorithm are available in Python/Scipy
and MATLAB. More recent work has produced variations on the algorithm with
better convergence &lt;a class="citation-reference" href="#filip" id="id2"&gt;[Filip]&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;From a practical perspective, a naive implementation of a FIR decimator (that
is, a FIR followed by a decimation stage) is computationally inefficient.
Here, too, there's an obvious path to follow. Polyphase techniques
&lt;a class="citation-reference" href="#vaidyanathan" id="id3"&gt;[Vaidyanathan]&lt;/a&gt; can be used to decompose a single, large FIR into a set of
parallel FIRs operating at a reduced data rate.&lt;/p&gt;
&lt;p&gt;As flexible and useful as FIR decimators are, there are a few corner cases
where they don't produce adequate designs:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;When the decimation ratios involved are very high, the number of FIR
coefficients needed to meet performance requirements grows.  Even if the
Parks-McClellan algorithm does converge to an usable FIR, the resulting
coefficient vector may be impractical to use even after polyphase
decomposition.&lt;/li&gt;
&lt;li&gt;When memory (coefficient and signal buffers) is very highly constrained (i.e.
in an FPGA, or when processing many signals in a design.) The polyphase
decomposition reduces the computational burden associated with the FIR, but
does nothing for the amount of memory required.&lt;/li&gt;
&lt;li&gt;When an FIR does not offer adequate flexibility (see, for example, the
variable-sampling-rate trick described below.)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In these situations, a CIC is an interesting alternative.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="introducing-the-cic-filter"&gt;
&lt;h2&gt;&lt;a class="toc-backref" href="#id10"&gt;Introducing the CIC Filter&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A CIC, or Cascaded Integrator-Comb, is a filter that's much more restrictive
than an FIR. It has a very wide transition region and is only really effective
as an anti-aliasing filter for very narrowband signals. However, it's
computationally extremely efficient (it requires only adders and registers, and
relatively few of each) and its shortcomings can be corrected. When paired with
a conventional FIR, the resulting compound decimator plays to the strengths of
each.&lt;/p&gt;
&lt;img alt="" class="align-center" src="/images/ciccomp/signal_path.png" /&gt;
&lt;div class="line-block"&gt;
&lt;div class="line"&gt;&lt;br /&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The original CIC paper &lt;a class="citation-reference" href="#hogenauer" id="id4"&gt;[Hogenauer]&lt;/a&gt; is among my favourite DSP references. It is
well written and approachable, and revolves around a single mathematical trick
so filthy it's genuinely worth celebrating. Please stop here and go find read
the original paper.&lt;/p&gt;
&lt;p&gt;Assuming you have skimmed the original CIC paper, I will now pull out several
tidbits.  (Note that I'm focused on decimators, here, but there is always a
dual development that applies equally to interpolators.)&lt;/p&gt;
&lt;p&gt;In the following, we assume the compound decimation structure shown above, in
which large decimation factors are dealt with by the CIC. The FIR exists only
to compensate or &amp;quot;clean up&amp;quot; passband droop imposed by the CIC, and decimates by
a final factor of 2 because it is convenient and efficient to do so.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="a-magic-trick-small-angle-approximation"&gt;
&lt;h2&gt;&lt;a class="toc-backref" href="#id11"&gt;A Magic Trick: Small-Angle Approximation&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The amplitude response for a CIC decimator is (using the notation from
&lt;a class="citation-reference" href="#hogenauer" id="id5"&gt;[Hogenauer]&lt;/a&gt;):&lt;/p&gt;
&lt;p&gt;$$A(f) = \left[ \frac{\sin (\pi M f)}{\sin \left( \frac{\pi f}{R}\right)} \right]^N$$&lt;/p&gt;
&lt;p&gt;The terms in this equation are defined as follows:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;span class="math"&gt;\(N\)&lt;/span&gt; is the number of stages in the CIC filter,&lt;/li&gt;
&lt;li&gt;&lt;span class="math"&gt;\(M\)&lt;/span&gt; is a differential delay (a tunable parameter, though I only ever use 1),&lt;/li&gt;
&lt;li&gt;&lt;span class="math"&gt;\(R\)&lt;/span&gt; is the CIC's rate-change parameter, and&lt;/li&gt;
&lt;li&gt;&lt;span class="math"&gt;\(f\)&lt;/span&gt;, here, is a normalized frequency in which 0.5 corresponds to the Nyquist rate.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Hogenauer notes the small-angle approximation for the denominator term:&lt;/p&gt;
&lt;p&gt;$$\newcommand{\sinc}{\mathop{\rm sinc}\nolimits}
A(f) \approx \left[ RM \right]^N \sinc^N(\pi M f)$$&lt;/p&gt;
&lt;p&gt;where &lt;span class="math"&gt;\(\sinc(x) = \sin (\pi x)/(\pi x)\)&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;Let's assume our compensation filter will only correct the frequency-dependent
portions of this expression. (When &lt;span class="math"&gt;\([RM]^N\)&lt;/span&gt; is a power of 2, as they are
in my case, these gains are typically corrected using bit shifts, which are
free in an FPGA.) We are left with the frequency-dependent portion of the
expression&lt;/p&gt;
&lt;p&gt;$$\sinc^N \left( \pi M f \right)$$&lt;/p&gt;
&lt;p&gt;To correct for this amplitude droop, the FIR must impose the inverse gain
on its passband:&lt;/p&gt;
&lt;p&gt;$$C(f) = \sinc^{-N}(\pi Mf)$$&lt;/p&gt;
&lt;p&gt;for &lt;span class="math"&gt;\(f\)&lt;/span&gt; over a passband extending as high as the normalized frequency 1/4
(that is, the Nyquist rate at the FIR's output, remembering that it is also has
a decimation-by-2 rate change function.) In reality, the filter's passband edge
must be relaxed below the Nyquist rate to introduce a transition region,
allowing the filter's design to be tractable.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;The decimation rate R does not appear in this expression&lt;/em&gt;! That is, provided
the small-angle approximation is appropriate, a single single, fixed
compensation FIR will suffice for any CIC decimation rate. This provides an
easy way to build a signal path that's adaptable to multiple operating
scenarios without being redesigned each time.&lt;/p&gt;
&lt;p&gt;We have motivated the need for a compensating filter, and proposed a structure
for it. We have also calculated the required passband amplitude to correct for
droop in the CIC's passband. We are finally ready to calculate it.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="compensating-cic-filters"&gt;
&lt;h2&gt;&lt;a class="toc-backref" href="#id12"&gt;Compensating CIC Filters&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Of the dominant signal-processing packages, unfortunately, only MATLAB provides
&lt;a class="reference external" href="https://www.mathworks.com/help/dsp/ref/fdesign.ciccomp.html"&gt;the necessary machinery&lt;/a&gt; to create a
CIC compensator FIR &amp;quot;out-of-the-box&amp;quot;. In the past, I have managed to scrounge
up a MATLAB installation in the rare case I need it. However, my lab shifted
wholesale to Python a decade ago, and I'm otherwise completely MATLAB-free.
Sorry, Mathworks, it's time to move on.&lt;/p&gt;
&lt;p&gt;Here are a few open-source Parks-McClellan or Remez implementations:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="https://octave.sourceforge.io/signal/function/remez.html"&gt;Octave-forge's Remez implementation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="https://docs.scipy.org/doc/scipy/reference/generated/scipy.signal.remez.html"&gt;Python's scipy.signal library&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="https://github.com/sfilip/firpm"&gt;Silviu-Ioan Filip's stability improvements&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="https://liquidsdr.org/blog/firdespm-invsinc/"&gt;An inverse-sinc filter tutorial from Liquid SDR&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://michaelgellis.tripod.com/dsp/pgm21.html"&gt;The original FORTRAN code&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Unfortunately, none of these implementations is suitable on its own. The Liquid
SDR implementation allows a callback to inject the desired amplitude responses
&lt;span class="math"&gt;\(C(f)\)&lt;/span&gt;; however, this implementation did not converge well enough for me
to use it. Where other implementations of the Parks-McClellan algorithm
admitted a stepwise or piecewise-linear approximation to &lt;span class="math"&gt;\(C(f)\)&lt;/span&gt;,
experiments with this approach were far too brittle to produce usable results.&lt;/p&gt;
&lt;p&gt;I was, however, able to add a callback-enabled version of Silviu-Ioan Filip's
code.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="the-solution"&gt;
&lt;h2&gt;&lt;a class="toc-backref" href="#id13"&gt;The Solution&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I began with the source code here:&lt;/p&gt;
&lt;div class="line-block"&gt;
&lt;div class="line"&gt;&lt;a class="reference external" href="https://github.com/sfilip/firpm"&gt;https://github.com/sfilip/firpm&lt;/a&gt; &lt;a class="citation-reference" href="#filip" id="id6"&gt;[Filip]&lt;/a&gt;&lt;/div&gt;
&lt;div class="line"&gt;&lt;br /&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;This code contains three implementations of an extended Parks-McClellan
algorithm: two using underlying C types (&lt;code&gt;double&lt;/code&gt; and &lt;code&gt;long
double&lt;/code&gt;), and one using an arbitrary-precision library (Pavel Holoborodko's
excellent &lt;a class="reference external" href="http://www.holoborodko.com/pavel/mpfr"&gt;C++ wrappers&lt;/a&gt; for the also
excellent &lt;a class="reference external" href="https://www.mpfr.org/"&gt;GNU MPFR&lt;/a&gt; library.) I opted for the third,
since I am more interested in limiting developer commitment than maximizing
computational efficiency.&lt;/p&gt;
&lt;p&gt;(As an aside, this code would benefit greatly from some refactoring by an
experienced C++ developer.)&lt;/p&gt;
&lt;p&gt;My modifications are contained in a new repository here:&lt;/p&gt;
&lt;div class="line-block"&gt;
&lt;div class="line"&gt;&lt;a class="reference external" href="https://bitbucket.org/gsmecher/ciccomp"&gt;https://bitbucket.org/gsmecher/ciccomp&lt;/a&gt;&lt;/div&gt;
&lt;div class="line"&gt;&lt;br /&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;img alt="" class="align-center" src="/images/ciccomp/ciccomp_spectrum.png" /&gt;
&lt;div class="line-block"&gt;
&lt;div class="line"&gt;&lt;br /&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;img alt="" class="align-center" src="/images/ciccomp/ciccomp_impulse.png" /&gt;
&lt;div class="line-block"&gt;
&lt;div class="line"&gt;&lt;br /&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Enjoy!&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="references"&gt;
&lt;h2&gt;&lt;a class="toc-backref" href="#id14"&gt;References&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The following links are often behind IEEE's paywall. However, the papers
referenced here are &amp;quot;classics&amp;quot; and are easily available with a little creative
searching. Both the &lt;a class="citation-reference" href="#vaidyanathan" id="id7"&gt;[Vaidyanathan]&lt;/a&gt; and &lt;a class="citation-reference" href="#hogenauer" id="id8"&gt;[Hogenauer]&lt;/a&gt; references are among my
all-time favourites for both content and presentation.&lt;/p&gt;
&lt;table class="docutils citation" frame="void" id="vaidyanathan" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label" /&gt;&lt;col /&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;[Vaidyanathan]&lt;/td&gt;&lt;td&gt;&lt;em&gt;(&lt;a class="fn-backref" href="#id3"&gt;1&lt;/a&gt;, &lt;a class="fn-backref" href="#id7"&gt;2&lt;/a&gt;)&lt;/em&gt; P.P. Vaidyanathan, &amp;quot;Multirate Digital filters, filter banks,
polyphase networks, and applications: a tutorial&amp;quot;. In Proc. IEEE, vol. 78, Jan. 1990.
&lt;a class="reference external" href="https://ieeexplore.ieee.org/document/52200"&gt;https://ieeexplore.ieee.org/document/52200&lt;/a&gt;)&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table class="docutils citation" frame="void" id="hogenauer" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label" /&gt;&lt;col /&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;[Hogenauer]&lt;/td&gt;&lt;td&gt;&lt;em&gt;(&lt;a class="fn-backref" href="#id4"&gt;1&lt;/a&gt;, &lt;a class="fn-backref" href="#id5"&gt;2&lt;/a&gt;, &lt;a class="fn-backref" href="#id8"&gt;3&lt;/a&gt;)&lt;/em&gt; E. Hogenauer, &amp;quot;An Economical Class of Digital Filters for Decimation and
Interpolation&amp;quot;. In IEEE Trans. Acoustics, Speech, and Signal Processing, vol. 29,
Apr. 1981. &lt;a class="reference external" href="https://ieeexplore.ieee.org/document/1163535"&gt;https://ieeexplore.ieee.org/document/1163535&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table class="docutils citation" frame="void" id="parks-mcclellan" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label" /&gt;&lt;col /&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;&lt;a class="fn-backref" href="#id1"&gt;[Parks-McClellan]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;J.H.McClellan and T.W.Parks, &amp;quot;A Personal History of the Parks-McClellan
Algorithm&amp;quot;. In IEEE Signal Processing Magazine, vol. 22, Mar. 2005.
&lt;a class="reference external" href="https://ieeexplore.ieee.org/document/1406492"&gt;https://ieeexplore.ieee.org/document/1406492&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table class="docutils citation" frame="void" id="filip" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label" /&gt;&lt;col /&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;[Filip]&lt;/td&gt;&lt;td&gt;&lt;em&gt;(&lt;a class="fn-backref" href="#id2"&gt;1&lt;/a&gt;, &lt;a class="fn-backref" href="#id6"&gt;2&lt;/a&gt;)&lt;/em&gt; Silviu-Ioan Filip, &amp;quot;A Robust and Scalable Implementation of the
Parks-McClellan Algorithm for Designing FIR Filters&amp;quot;. In ACM Trans. Mathematical Software,
Vol. 43, Aug. 2016. &lt;a class="reference external" href="https://dl.acm.org/citation.cfm?id=2904902"&gt;https://dl.acm.org/citation.cfm?id=2904902&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;script type='text/javascript'&gt;if (!document.getElementById('mathjaxscript_pelican_#%@#$@#')) {
    var align = "center",
        indent = "0em",
        linebreak = "false";

    if (false) {
        align = (screen.width &lt; 768) ? "left" : align;
        indent = (screen.width &lt; 768) ? "0em" : indent;
        linebreak = (screen.width &lt; 768) ? 'true' : linebreak;
    }

    var mathjaxscript = document.createElement('script');
    mathjaxscript.id = 'mathjaxscript_pelican_#%@#$@#';
    mathjaxscript.type = 'text/javascript';
    mathjaxscript.src = 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.3/latest.js?config=TeX-AMS-MML_HTMLorMML';

    var configscript = document.createElement('script');
    configscript.type = 'text/x-mathjax-config';
    configscript[(window.opera ? "innerHTML" : "text")] =
        "MathJax.Hub.Config({" +
        "    config: ['MMLorHTML.js']," +
        "    TeX: { extensions: ['AMSmath.js','AMSsymbols.js','noErrors.js','noUndefined.js'], equationNumbers: { autoNumber: 'none' } }," +
        "    jax: ['input/TeX','input/MathML','output/HTML-CSS']," +
        "    extensions: ['tex2jax.js','mml2jax.js','MathMenu.js','MathZoom.js']," +
        "    displayAlign: '"+ align +"'," +
        "    displayIndent: '"+ indent +"'," +
        "    showMathMenu: true," +
        "    messageStyle: 'normal'," +
        "    tex2jax: { " +
        "        inlineMath: [ ['\\\\(','\\\\)'] ], " +
        "        displayMath: [ ['$$','$$'] ]," +
        "        processEscapes: true," +
        "        preview: 'TeX'," +
        "    }, " +
        "    'HTML-CSS': { " +
        "        availableFonts: ['STIX', 'TeX']," +
        "        preferredFont: 'STIX'," +
        "        styles: { '.MathJax_Display, .MathJax .mo, .MathJax .mi, .MathJax .mn': {color: 'inherit ! important'} }," +
        "        linebreaks: { automatic: "+ linebreak +", width: '90% container' }," +
        "    }, " +
        "}); " +
        "if ('default' !== 'default') {" +
            "MathJax.Hub.Register.StartupHook('HTML-CSS Jax Ready',function () {" +
                "var VARIANT = MathJax.OutputJax['HTML-CSS'].FONTDATA.VARIANT;" +
                "VARIANT['normal'].fonts.unshift('MathJax_default');" +
                "VARIANT['bold'].fonts.unshift('MathJax_default-bold');" +
                "VARIANT['italic'].fonts.unshift('MathJax_default-italic');" +
                "VARIANT['-tex-mathit'].fonts.unshift('MathJax_default-italic');" +
            "});" +
            "MathJax.Hub.Register.StartupHook('SVG Jax Ready',function () {" +
                "var VARIANT = MathJax.OutputJax.SVG.FONTDATA.VARIANT;" +
                "VARIANT['normal'].fonts.unshift('MathJax_default');" +
                "VARIANT['bold'].fonts.unshift('MathJax_default-bold');" +
                "VARIANT['italic'].fonts.unshift('MathJax_default-italic');" +
                "VARIANT['-tex-mathit'].fonts.unshift('MathJax_default-italic');" +
            "});" +
        "}";

    (document.body || document.getElementsByTagName('head')[0]).appendChild(configscript);
    (document.body || document.getElementsByTagName('head')[0]).appendChild(mathjaxscript);
}
&lt;/script&gt;</content><category term="DSP"></category><category term="CIC"></category><category term="FPGA"></category></entry><entry><title>Tworoutines in Python</title><link href="http://threespeedlogic.com/python-tworoutines.html" rel="alternate"></link><published>2018-11-19T00:00:00-08:00</published><updated>2018-11-19T00:00:00-08:00</updated><author><name>Graeme Smecher</name></author><id>tag:threespeedlogic.com,2018-11-19:/python-tworoutines.html</id><summary type="html">&lt;p class="first last"&gt;An interesting, and possibly doomed, method of combining async and synchronous Python code&lt;/p&gt;
</summary><content type="html">&lt;div class="figure align-center"&gt;
&lt;img alt="" src="/images/tworoutine/tworoutine.png" /&gt;
&lt;/div&gt;
&lt;div class="line-block"&gt;
&lt;div class="line"&gt;&lt;br /&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;This article describes a style of coding in Python that permits easy mixing of
synchronous and asynchronous code. As part of the control software for large
microwave telescopes (including the &lt;a class="reference external" href="https://pole.uchicago.edu/spt/"&gt;South Pole Telescope&lt;/a&gt;), we have been
using this style of code under a Tornado / Python 2.x stack with success.&lt;/p&gt;
&lt;p&gt;Unfortunately, architectural changes in Python 3.7 conspire against the
&lt;cite&gt;&amp;#64;tworoutine&lt;/cite&gt;.  In the hopes of contributing to a lively discussion about
Python's asynchronous ecosystem, we describe why they have been so useful to
us.&lt;/p&gt;
&lt;div class="contents topic" id="table-of-contents"&gt;
&lt;p class="topic-title"&gt;Table of Contents&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference internal" href="#introduction" id="id2"&gt;Introduction&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#coding-for-telescopes" id="id3"&gt;Coding for Telescopes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#enter-the-tworoutine" id="id4"&gt;Enter the &lt;cite&gt;&amp;#64;tworoutine&lt;/cite&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#lament-of-course-there-s-a-catch" id="id5"&gt;Lament: Of Course There's A Catch&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#disclaimer" id="id6"&gt;Disclaimer&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="introduction"&gt;
&lt;h2&gt;&lt;a class="toc-backref" href="#id2"&gt;Introduction&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Asynchronous coding in Python was pioneered by third-party libraries like
&lt;a class="reference external" href="https://twistedmatrix.com"&gt;Twisted&lt;/a&gt;, &lt;a class="reference external" href="https://tornadoweb.org"&gt;Tornado&lt;/a&gt;, and &lt;a class="reference external" href="https://gevent.org"&gt;gevent&lt;/a&gt;. An &amp;quot;official&amp;quot; event-loop implementation
landed in &lt;a class="reference external" href="https://docs.python.org/3.4/library/asyncio-task.html"&gt;Python 3.4&lt;/a&gt;, and was expanded
significantly in &lt;a class="reference external" href="https://docs.python.org/3/library/asyncio.html"&gt;Python 3.7&lt;/a&gt;. A new breed of asynchronous
libraries like &lt;a class="reference external" href="http://github.com/dabaez/curio"&gt;curio&lt;/a&gt; and &lt;a class="reference external" href="http://trio.readthedocs.io"&gt;trio&lt;/a&gt; continue to push the boundaries beyond
what's &amp;quot;normal&amp;quot; in the space.&lt;/p&gt;
&lt;p&gt;There are also some excellent (and opinionated) articles about Python's
asynchronous ecosystem. I don't always agree with them and I don't intend to
recapitulate them.  To allow me to get the point, though, I will provide a few
links that set the stage for what follows.&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="https://www.python.org/dev/peps/pep-3156/"&gt;PEP 3156 -- Asynchronous IO Support Rebooted: the &amp;quot;asyncio&amp;quot; Module&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://lucumr.pocoo.org/2016/10/30/i-dont-understand-asyncio/"&gt;I don't understand Python's Asyncio&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="https://snarky.ca/how-the-heck-does-async-await-work-in-python-3-5/"&gt;How the heck does async/await work in Python 3.5?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="https://hackernoon.com/controlling-python-async-creep-ec0a0f4b79ba"&gt;Controlling Python Async Creep&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Of these, the last one is probably the most interesting because it identifies
and attempts to address the same problem we run into when designing telescope
tuning software: asynchronous and synchronous coding styles occupy different
universes in Python, but it is exteremly useful to mix them freely.&lt;/p&gt;
&lt;p&gt;To motivate mixing synchronous and asynchronous code, here is a short
description of the kind of code we write for tuning telescopes.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="coding-for-telescopes"&gt;
&lt;h2&gt;&lt;a class="toc-backref" href="#id3"&gt;Coding for Telescopes&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;My day job includes work on CMB telescopes including the &lt;a class="reference external" href="https://pole.uchicago.edu/spt/"&gt;South Pole
Telescope&lt;/a&gt; in &lt;a class="reference external" href="https://goo.gl/maps/SNnrUyLcFkq"&gt;Antarctica&lt;/a&gt; and the &lt;a class="reference external" href="https://arxiv.org/abs/1512.07299"&gt;Simons
Array&lt;/a&gt; on Chile's Atacama Plateau.&lt;/p&gt;
&lt;p&gt;The &lt;a class="reference external" href="https://arxiv.org/abs/1407.3161"&gt;readout electronics&lt;/a&gt; in these
telescopes is a large array of &lt;a class="reference external" href="https://arxiv.org/pdf/1008.4587.pdf"&gt;software defined radios&lt;/a&gt;, with many thousands of transmitters
and receivers used to bias and measure the leftover signature of the Big Bang.
These radios are implemented in hundreds of custom boards hosting &lt;a class="reference external" href="https://www.xilinx.com/products/silicon-devices/fpga/kintex-7.html"&gt;FPGAs&lt;/a&gt;
installed in crates near the telescope, and controlled by a PC.  This PC gets
the system up and running, controls cryogenic refrigerators, aims the
telescope, and captures the torrent of data it produces.&lt;/p&gt;
&lt;p&gt;The entire tuning, control, and analysis stack makes very heavy use of Python,
along with C, C++, and VHDL. (I am inexpressibly grateful to the many
open-source communities we rely on, and it is a great privilege when I can give
back in some capacity.)&lt;/p&gt;
&lt;p&gt;As you can imagine, we don't just deploy code straight onto the telescope.
Along with the telescopes themselves are small-scale installations ranging from
a circuit board or two on a benchtop, to crates of cryogenic equipment at
university labs around the world. During development, code might be running
in a &lt;a class="reference external" href="http://jupyter.org/"&gt;Jupyter notebook&lt;/a&gt; or an &lt;a class="reference external" href="https://ipython.org/"&gt;IPython shell&lt;/a&gt;, perhaps with a small crate of electronics or nothing
at all. Here, interactive REPL sessions are used to prototype algorithms,
explore data, and try out new tuning and analysis techniques.&lt;/p&gt;
&lt;p&gt;For an algorithm to be useful in deployment, however, it needs to run at scale.
Here's where we use asynchronous code heavily: command interactions with many
hundreds of circuit boards are a natural fit for asynchronous coding styles.
This leads to the following workflow:&lt;/p&gt;
&lt;div class="figure align-center"&gt;
&lt;img alt="" src="/images/tworoutine/separate_design_flow.png" /&gt;
&lt;p class="caption"&gt;Design flow, with separate asynchronous/synchronous implementations:&lt;/p&gt;
&lt;div class="legend"&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Prototype code, probably synchronous and focused on proofing out an
algorithm or technique;&lt;/li&gt;
&lt;li&gt;Test for function on a small-scale deployment, likely in an interactive
(ipython) environment;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Re-code&lt;/em&gt; the algorithm using an asynchronous style; and&lt;/li&gt;
&lt;li&gt;Integration testing, optimization, and deployment.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;This approach has advantages:&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;When developing a proof-of-concept, developers are able to ignore
performance and focus on the problem (physics, instrumentation, cryogenics,
electronics) that they are attempting to address.&lt;/li&gt;
&lt;li&gt;During prototyping, when interactive exploration is most useful, synchronous
code promotes use of environments such as IPython or Jupyter.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;However, this workflow has three major disadvantages:&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;It's clumsy: it requires writing and testing a synchronous version, then
shifting it wholesale to an asynchronous environment.  It is easy to imagine
this workflow looping back on itself as bugs are discovered or introduced
along the way.&lt;/li&gt;
&lt;li&gt;The synchronous version &lt;em&gt;never stops being useful&lt;/em&gt;, despite not scaling to
telescope-level performance. We would often much rather have the simpler
semantics, more predictable control flow, and shorter error traces associated
with a synchronous call when debugging or experimenting.  In addition, it can
be conveniently invoked in a REPL environment -- invaluable if the telescope is
operating and we need to do some quick hand-tuning.&lt;/li&gt;
&lt;li&gt;It's not composable. Over the years, we have build up libraries of useful
tuning and control algorithms, and as long as synchronous and asynchronous
code is kept distinct, we cannot meaningfully compose algorithms out of
smaller pieces without two implementations of everything.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Asking developers to maintaining two versions under different coding idioms
(and expecting to keep the versions synchronized) is resolving a technical flaw
by requiring skilled labourers to do menial work; this is often an expensive
mistake.  (Interactive use of asynchronous code is getting easier in IPython
7.0 due to the &lt;a class="reference external" href="https://ipython.readthedocs.io/en/stable/interactive/autoawait.html"&gt;autoawait&lt;/a&gt;
functionality. This extension addresses the second but not the third point.)&lt;/p&gt;
&lt;p&gt;Instead, we are looking for a way to freely mix asynchronous and synchronous
coding styles.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="enter-the-tworoutine"&gt;
&lt;h2&gt;&lt;a class="toc-backref" href="#id4"&gt;Enter the &lt;cite&gt;&amp;#64;tworoutine&lt;/cite&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;What's a &lt;cite&gt;&amp;#64;tworoutine&lt;/cite&gt;? It is a &lt;em&gt;synchronous&lt;/em&gt; wrapper around an &lt;em&gt;asynchronous&lt;/em&gt;
function, allowing a single piece of code to be called in either idiom.&lt;/p&gt;
&lt;p&gt;(If you are following along at home, you will need the &lt;a class="reference external" href="https://github.com/gsmecher/tworoutine"&gt;source code&lt;/a&gt;. You will also need &lt;a class="reference external" href="https://github.com/erdewit/nest_asyncio"&gt;nest_asyncio&lt;/a&gt;.)&lt;/p&gt;
&lt;pre class="code python literal-block"&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;tworoutine&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;asyncio&lt;/span&gt;

&lt;span class="nd"&gt;&amp;#64;tworoutine.tworoutine&lt;/span&gt;
&lt;span class="n"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;double_slowly&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;await&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;How can we call this function synchronously? Just call it!&lt;/p&gt;
&lt;pre class="code python literal-block"&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;double_slowly&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="mi"&gt;2&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;How did this work? The &lt;cite&gt;&amp;#64;tworoutine&lt;/cite&gt; decorator returns a class whose &lt;cite&gt;__call__&lt;/cite&gt;
method is a synchronous wrapper that obtains an event loop and invokes the
asynchronous code, blocking until it's complete. Because we want synchronous
calling to be convenient and carpal-tunnel-friendly, that's the default.&lt;/p&gt;
&lt;p&gt;If there's already an event loop running, this code is reasonably efficient
(aside from being a blocking call, of course!) Any asynchronous events already
queued in the event loop are allowed to proceed alongside this one. Only the
current execution context is blocked until the coroutine completes.&lt;/p&gt;
&lt;p&gt;So much for synchronous calls. How can we call this function asynchronously? We
first have to undo or &amp;quot;invert&amp;quot; the wrapper and obtain a reference back to the
coroutine.&lt;/p&gt;
&lt;pre class="code python literal-block"&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;double_slowly&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;coroutine&lt;/span&gt; &lt;span class="nb"&gt;object&lt;/span&gt; &lt;span class="n"&gt;double_slowly&lt;/span&gt; &lt;span class="n"&gt;at&lt;/span&gt; &lt;span class="mh"&gt;0x7f5d494fd348&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;With the exception of the invert operator around the function name, this is
ordinary asynchronous code; there is no additional overhead except for the
operator itself.  Here is a complete example showing mixed coding styles within
an event loop:&lt;/p&gt;
&lt;pre class="code python literal-block"&gt;
&lt;span class="n"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="c1"&gt;# Run asynchronously&lt;/span&gt;
    &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;await&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;double_slowly&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Run synchronously within an event loop&lt;/span&gt;
    &lt;span class="n"&gt;r2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;double_slowly&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# try asynchronous entry&lt;/span&gt;
&lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;The obvious benefit, here, is the ability to call asynchronous code
synchronously when we're too lazy to carry around an event loop or deal with
the &lt;a class="reference external" href="https://medium.com/&amp;#64;davealexis/this-is-why-i-consider-the-async-await-pattern-to-be-like-a-virus-e029d95fcba1"&gt;turtles-all-the-way-down&lt;/a&gt;
nature of Python's asynchronous coding idiom.&lt;/p&gt;
&lt;div class="figure align-center"&gt;
&lt;img alt="" src="/images/tworoutine/tworoutine_design_flow.png" /&gt;
&lt;p class="caption"&gt;Design flow with &lt;cite&gt;&amp;#64;tworoutine&lt;/cite&gt;. The synchronous and asynchronous
implementations are replaced with a single implementation that can mix
idioms.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="lament-of-course-there-s-a-catch"&gt;
&lt;h2&gt;&lt;a class="toc-backref" href="#id5"&gt;Lament: Of Course There's A Catch&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;cite&gt;&amp;#64;tworoutine&lt;/cite&gt;'s days are probably numbered. This style of coding has been
implicitly but firmly rejected by Python developers:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="https://bugs.python.org/issue22239"&gt;Issue 22239: asyncio: nested event loop&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We have been using this approach (implemented on Python 2.7 and Tornado &amp;lt;4.5)
for several years now at the South Pole and elsewhere, and we will have to
adapt.&lt;/p&gt;
&lt;p&gt;To complete a synchronous &lt;cite&gt;&amp;#64;tworoutine&lt;/cite&gt; call, we need to obtain an event loop,
schedule the asynchronous (decorated) call, and block until it is complete.
Currently there is no way to do that in Python 3.7 asyncio without patching it.
Asynchronous code at any point in the call stack must be linked to the event
loop via asynchronous calls only, all the way up.&lt;/p&gt;
&lt;p&gt;To work around this problem in the Python 3.7 code shown here, I have used the
&lt;a class="reference external" href="https://github.com/erdewit/nest_asyncio"&gt;nest_asyncio&lt;/a&gt; monkey patch. It is a
short and effective piece of code, but it runs against Python orthodoxy and
adopting this kind of patch in production risks being stranded by changes to
Python's core libraries.&lt;/p&gt;
&lt;p&gt;Without this patch, we are able to upgrade as far as Tornado 4.5 on Python 3.x,
but &lt;a class="reference external" href="https://github.com/jupyter/notebook/issues/3397"&gt;Tornado 5.0&lt;/a&gt; moves to
an asyncio event loop and we are suddenly unable to upgrade.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="disclaimer"&gt;
&lt;h2&gt;&lt;a class="toc-backref" href="#id6"&gt;Disclaimer&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The code examples here have been forward-ported from Python 2.7 and Tornado 4.5
to Python 3.7 and &amp;quot;pure&amp;quot; asyncio. It's an experiment -- this is not
production code!&lt;/p&gt;
&lt;/div&gt;
</content><category term="Python"></category><category term="asyncio"></category></entry><entry><title>Exploring the Orbital Radiation Environment with Python</title><link href="http://threespeedlogic.com/python-space-weather.html" rel="alternate"></link><published>2018-06-24T00:00:00-07:00</published><updated>2018-06-24T00:00:00-07:00</updated><author><name>Graeme Smecher</name></author><id>tag:threespeedlogic.com,2018-06-24:/python-space-weather.html</id><summary type="html">&lt;p class="first last"&gt;A look through the GOES satellite data archive&lt;/p&gt;
</summary><content type="html">&lt;p&gt;This page describes how to retrieve proton-detector data from satellite
archives provided by the US National Oceanic and Atmospheric Administration
(NOAA). By applying some Python code to this data, we will plot measurements of
the radiation environment captured by satellites in geosynchronous orbit.&lt;/p&gt;
&lt;div class="contents topic" id="table-of-contents"&gt;
&lt;p class="topic-title"&gt;Table of Contents&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference internal" href="#the-goes-satellites" id="id1"&gt;The GOES Satellites&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#the-problem-with-protons" id="id2"&gt;The Problem with Protons&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#getting-started" id="id3"&gt;Getting Started&lt;/a&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class="reference internal" href="#the-fetch-script" id="id4"&gt;The Fetch Script&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#parsing-goes-csv" id="id5"&gt;Parsing GOES CSV&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#the-analysis-script" id="id6"&gt;The Analysis Script&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#quiet-conditions" id="id7"&gt;Quiet Conditions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#solar-storms" id="id8"&gt;Solar Storms&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#conclusions" id="id9"&gt;Conclusions&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="the-goes-satellites"&gt;
&lt;h2&gt;&lt;a class="toc-backref" href="#id1"&gt;The GOES Satellites&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;First, a little back story. In this material, I lean heavily on the Wikipedia
pages on the &lt;a class="reference external" href="https://en.wikipedia.org/wiki/Geostationary_Operational_Environmental_Satellite"&gt;GOES satellites&lt;/a&gt; — they are a treasure trove and I thoroughly
recommend you go wandering in Wikipedia-land.&lt;/p&gt;
&lt;p&gt;For over 40 years, the US National Oceanic and Atmospheric Administration
(NOAA) has operated a series of spacecraft called the Geostationary Operational
Environmental Satellites (GOES). Starting with &lt;a class="reference external" href="https://en.wikipedia.org/wiki/GOES_1"&gt;GOES-1&lt;/a&gt; in 1975 (manufactured
by Ford Aerospace — yes, that Ford), most of these satellites were
successfully launched and served for many years, and have since been
decomissioned.&lt;/p&gt;
&lt;p&gt;The GOES family of satellites is still going strong: &lt;a class="reference external" href="https://en.wikipedia.org/wiki/GOES_15"&gt;GOES-15&lt;/a&gt; through
&lt;a class="reference external" href="https://en.wikipedia.org/wiki/GOES_17"&gt;GOES-17&lt;/a&gt; are in orbit and either functioning, or standing by in case a
repalacement is needed.  &lt;a class="reference external" href="https://www.nasa.gov/content/goes"&gt;Imagery from GOES-17&lt;/a&gt; — launched just a few months
ago — is already available on NASA's web site.  Additional GOES launches are
scheduled in 2020 and 2024.&lt;/p&gt;
&lt;p&gt;Satellite technology has changed a lot in since 1975, and consequently, the
instruments on these satellites vary quite a bit. Different GOES satellites
have included:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Proton, alpha-particle, X-ray, and electron flux detectors,&lt;/li&gt;
&lt;li&gt;Earth-facing optical, infrared, and near-infrared cameras,&lt;/li&gt;
&lt;li&gt;Solar imagers,&lt;/li&gt;
&lt;li&gt;Magnetometers&lt;/li&gt;
&lt;li&gt;Lightning detectors, and&lt;/li&gt;
&lt;li&gt;Radio equipment for communicating with the Earth.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Since I am specifically interested in the proton detectors — data that's
readily available in a standard format from 1986 onwards — this is the data we
will investigate. First, though, why protons?&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="the-problem-with-protons"&gt;
&lt;h2&gt;&lt;a class="toc-backref" href="#id2"&gt;The Problem with Protons&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Radiation is bad for electronics. Energetic protons are a big component of the
radiation mixture in geosynchronous orbits.&lt;/p&gt;
&lt;p&gt;Electronics in a radioactive environment generally exhibit two kinds of effects
caused by radiation:&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;Long-term effects (Jargon: &amp;quot;Total Ionizing Dose&amp;quot; or &amp;quot;TID&amp;quot;), in which
radiation damage accumulates over time and leads to degradation and the
eventual and permanent failure of spacecraft electronics, and&lt;/li&gt;
&lt;li&gt;Short-term effects (Jargon: Single-Event Effects, Single-Event Upsets,
Single-Event Errors) caused by individual interactions between radiation and
spacecraft systems. These effects may flip a bit from its correct value or
generate a small transient signal that shouldn't be present.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;These radiation effects occur on the ground, too, but the Earth's atmosphere
absorbs most of the radiation that would otherwise scramble our electronics. On
the ground, we mostly (but not always!) ignore the remaining errors. If your
computer has ever inexplicably rebooted, the problem may have been cosmic
radiation.&lt;/p&gt;
&lt;p&gt;Back to space. These effects are not &lt;em&gt;only&lt;/em&gt; caused by protons, but especially
inside the spacecraft's shell where there is some shielding present, protons
are a good enough proxy for radiation levels that we can focus on just one type
of particle for now. (This is an useful simplification and a great way to get
experts — I am not one of them — to start arguing.)&lt;/p&gt;
&lt;p&gt;During solar storms, the arrival rates (fluxes) of protons are &lt;em&gt;orders of
magnitude&lt;/em&gt; higher than background conditions. The result? For long-term damage
(TID), the quiet conditions between solar storms don't accumulate enough damage
to matter at all.&lt;/p&gt;
&lt;p&gt;For short-term damage (SEE), errors do occur during quiet conditions, and
engineers do need to worry about their effects. However, the design of
spacecraft electronics must accommodate (and is typically driven by) the worst
conditions. For critical spacecraft systems (such as propulsion), survival is
not enough: these systems are sometimes required to operate without error
during during radiation events in order to maintain spacecraft function.&lt;/p&gt;
&lt;p&gt;The frequency, source, intensity, and particle mixtures associated with solar
radiation events are another good opportunity to fall down the Wikipedia hole.
However, it's time to come back to the premise of this article and add a little
Python code.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="getting-started"&gt;
&lt;h2&gt;&lt;a class="toc-backref" href="#id3"&gt;Getting Started&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;OK, let's get our hands dirty. The following Python code does not have terribly
esoteric requirements, but we do require the following:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Python 3.5 or newer (I use Debian's stock 3.6.6rc1 build),&lt;/li&gt;
&lt;li&gt;Asynchronous packages (&lt;a class="reference external" href="https://docs.python.org/3/library/asyncio.html"&gt;asyncio&lt;/a&gt;, &lt;a class="reference external" href="https://aiohttp.readthedocs.io/en/stable/"&gt;aiohttp&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Scientific packages (&lt;a class="reference external" href="https://numpy.org"&gt;numpy&lt;/a&gt;, &lt;a class="reference external" href="https://scipy.org"&gt;scipy&lt;/a&gt;, &lt;a class="reference external" href="https://matplotlib.org"&gt;matplotlib&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can download the source code from Bitbucket as follows:&lt;/p&gt;
&lt;pre class="code bash literal-block"&gt;
$ git clone git&amp;#64;bitbucket.org:gsmecher/goes-proton-python.git
$ &lt;span class="nb"&gt;cd&lt;/span&gt; goes-proton-python
&lt;/pre&gt;
&lt;p&gt;Because we make use of a large dataset, the processing pipeline is split into
two stages:&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;A script (fetch.py) that fetches GOES data from NOAA's archive into a local on-disk cache, and&lt;/li&gt;
&lt;li&gt;A script (analyze.py) that processes cached data (in bulk) and produces monthly radiation plots.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The first script is an attempt to be polite to the NOAA servers: we can (and
do) still download a large dataset fairly quickly, but at least we can avoid
downloading it more than once.&lt;/p&gt;
&lt;p&gt;The second script does a batch analysis (and is aggressively parallel — it's
your PC, so we have no need to be polite here.)&lt;/p&gt;
&lt;div class="section" id="the-fetch-script"&gt;
&lt;h3&gt;&lt;a class="toc-backref" href="#id4"&gt;The Fetch Script&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;(Source: &lt;a class="reference external" href="https://bitbucket.org/gsmecher/goes-proton-python/src/master/fetch.py"&gt;fetch.py&lt;/a&gt;.)&lt;/p&gt;
&lt;p&gt;Simply run&lt;/p&gt;
&lt;pre class="code bash literal-block"&gt;
$ ./fetch.py
&lt;/pre&gt;
&lt;p&gt;It has been a few years since I have developed Python code in earnest, and back
then, the codebase I maintained was firmly in Python 2.6 territory. We made use
of the wonderful asynchronous event loop provided by the Tornado project, and
while watching the development of Python's batteries-included asynchronous
framework I have often wished I could pull some of my older code into the more
modern style. Bulk data fetch over HTTP was a great excuse to enter the brave
world of Python 3.5+ asynchronous coding.&lt;/p&gt;
&lt;p&gt;When you execute this script, it will create and populate a &lt;code&gt;_cache&lt;/code&gt;
directory. The default options fetch only a single year's worth of data for a
single satellite — if you want to download a larger dataset, you will have to
say so explicitly.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="parsing-goes-csv"&gt;
&lt;h3&gt;&lt;a class="toc-backref" href="#id5"&gt;Parsing GOES CSV&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;(Source: &lt;a class="reference external" href="https://bitbucket.org/gsmecher/goes-proton-python/src/master/goes.py"&gt;goes.py&lt;/a&gt;.)&lt;/p&gt;
&lt;p&gt;There are a number of ways of analyzing GOES data, including using the
open-source &lt;cite&gt;SPEDAS &amp;lt;http://spedas.org&amp;gt;_&lt;/cite&gt; software (which I have not tried).
If you are doing serious work, you are almost certainly better off &lt;em&gt;not&lt;/em&gt;
reinventing the wheel. Now, let's re-invent the wheel.&lt;/p&gt;
&lt;p&gt;The GOES dataset is large, and because we're talking about decades of history
and over a dozen satellites, it is natural to expect tension between the ideal
data format and the compatible data format. The data we use here is
formatted idiosyncraticically but not more than one would expect, given its
age and scope.&lt;/p&gt;
&lt;p&gt;GOES CSV is not strict CSV: it is CSV with embedded sub-tables, annotations,
and metadata. I have not attempted to write a general-purpose parser for the
overarching data format; rather, I have picked through the pieces of the file I
need and created a degenerate parser that only understands what it needs to.&lt;/p&gt;
&lt;p&gt;This code extends Python's &lt;a class="reference external" href="https://docs.python.org/3/library/csv.html#csv.DictReader"&gt;DictReader&lt;/a&gt; with some rudimentary variable type
conversion and teaches it to extract (and skip) the metadata blocks at the
top of the CSV file.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="the-analysis-script"&gt;
&lt;h3&gt;&lt;a class="toc-backref" href="#id6"&gt;The Analysis Script&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;(Source: &lt;a class="reference external" href="https://bitbucket.org/gsmecher/goes-proton-python/src/master/analyze.py"&gt;analyze.py&lt;/a&gt;.)&lt;/p&gt;
&lt;p&gt;Now that we can retrieve and parse GOES CSV data, we are ready to produce
graphics from it.  The analysis script leans heavily on &lt;a class="reference external" href="https://matplotlib.org"&gt;matplotlib&lt;/a&gt;,
which does not like threaded code. Hence, in order to generate a large volume
of independent plots, I used the &lt;a class="reference external" href="https://docs.python.org/3/library/multiprocessing.html"&gt;multiprocessing&lt;/a&gt; module instead.&lt;/p&gt;
&lt;p&gt;By default, this code will search the entire &lt;code&gt;_cache&lt;/code&gt; produced by the
&lt;code&gt;fetch.py&lt;/code&gt; script (above) and process everything in it, as quickly as it
can. For a large GOES cache, this can still take quite a while. The resulting
images (one per month per satellite) are placed in a &lt;code&gt;png/&lt;/code&gt; directory,
named per the original CSV data.&lt;/p&gt;
&lt;p&gt;Let's take a look.  Simply run:&lt;/p&gt;
&lt;pre class="code bash literal-block"&gt;
$ ./analyze.py
&lt;/pre&gt;
&lt;p&gt;This command produces a bunch of plots in the &lt;code&gt;png/&lt;/code&gt; directory.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="quiet-conditions"&gt;
&lt;h2&gt;&lt;a class="toc-backref" href="#id7"&gt;Quiet Conditions&lt;/a&gt;&lt;/h2&gt;
&lt;div class="figure"&gt;
&lt;img alt="" src="/images/goes/g06_eps_5m_19890101_19890131_corrected.png" /&gt;
&lt;p class="caption"&gt;January 1989 (corrected proton channels)&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;This is an ordinary quiet day during an active sunspot cycle (1989 was near the
peak of solar cycle 22). Before we proceed to a more spectacular example, let's
take a look at this plot and figure out what information it contains.&lt;/p&gt;
&lt;p&gt;This is a plot of proton intensity versus time, over the entire month of
January 1989. Using different colours, we show superimposed plots for a variety
of different sensors, each of which is sensitive to a range of proton kinetic
energies.  The vertical axis indicates proton flux, i.e. the number of
particles seen by the detector at a given time. Apart from a normalization
against proton kinetic energy, the units are logical. As you might expect,
protons with low kinetic energies (e.g. the blue curve) are present at higher
amounts than protons with higher energy levels (e.g. the magenta curve.)
Although the detectors are sensitive to different &lt;em&gt;ranges&lt;/em&gt; of proton energies,
and hence the underlying measurements are probably incommensurate between
sensors, the data has been normalized against these ranges to make comparisons
between different sensors &amp;quot;fair&amp;quot;. (Hence the &amp;quot;MeV&amp;quot; in the denominator in the
y-axis units.)&lt;/p&gt;
&lt;p&gt;In the blue trace, the satellite's orbital cycle in and out of the earth's
shadow is clearly visible. The &lt;a class="reference external" href="https://en.wikipedia.org/wiki/GOES_6"&gt;GOES-6&lt;/a&gt; satellite orbits relatively close to
the equator (14.7 degrees inclination) so it flies in and out of the Earth's
shadow once per day. (By definition, geosynchronous satellites have a day
that's exactly as long as ours. This is decidedly different from low-earth
orbits, where a satellite might orbit over a dozen times per day!)&lt;/p&gt;
&lt;p&gt;There are a few events visible on this day, particularly visible in the orange
band. However, the really high-energy proton detectors do not really see
anything except noise.&lt;/p&gt;
&lt;p&gt;March 1989 was a different story, as we will now see.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="solar-storms"&gt;
&lt;h2&gt;&lt;a class="toc-backref" href="#id8"&gt;Solar Storms&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In &lt;a class="reference external" href="https://en.wikipedia.org/wiki/March_1989_geomagnetic_storm"&gt;March 1989&lt;/a&gt;,
a coronal mass ejection launched an intense volley of radiation at the earth.
The resulting effects were substantial, even on the ground: Wikipedia claims a
large power outage in Quebec, and a panic among Cold War spooks fearing a
nuclear first strike.&lt;/p&gt;
&lt;div class="figure"&gt;
&lt;img alt="" src="/images/goes/g06_eps_5m_19890301_19890331_corrected.png" /&gt;
&lt;p class="caption"&gt;March 1989 (corrected proton channels)&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Since the Y axis is in logarithmic units, and since these plots are normalized
to wash away the effects of protons' kinetic energies, this plot understates
just how bad the radiation event in March 1989 was. (In fact, data is missing
for what is likely the worst portion of the event!)&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="conclusions"&gt;
&lt;h2&gt;&lt;a class="toc-backref" href="#id9"&gt;Conclusions&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;...and with those two plots, we have successfully downloaded, analyzed, and
plotted proton data from a geosynchronous satellite using Python — just as
promised. I will leave off with a couple of interesting links:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="https://en.wikipedia.org/wiki/Solar_storm_of_1859"&gt;The Carrington Event&lt;/a&gt;
was a severe geomagnetic storm occurring in 1859 — a long time ago, but
recent enough history to have a lively written record of the event's effects.&lt;/li&gt;
&lt;li&gt;While decomissioning a low-earth orbit generally involves dropping it into
the ocean, geosynchronous satellites are typically moved into a
&lt;a class="reference external" href="https://www.nesdis.noaa.gov/content/graveyard-orbits-and-satellite-afterlife"&gt;Graveyard orbit&lt;/a&gt; — far enough beyond the 30,000 km geostationary orbit to
stay out of trouble.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
</content><category term="Python"></category><category term="GOES"></category><category term="radiation"></category><category term="solar protons"></category></entry><entry><title>ICEboard: an FPGA / ARM Motherboard</title><link href="http://threespeedlogic.com/ICEboard.html" rel="alternate"></link><published>2018-06-06T13:36:55-07:00</published><updated>2018-06-06T13:36:55-07:00</updated><author><name>Graeme Smecher</name></author><id>tag:threespeedlogic.com,2018-06-06:/ICEboard.html</id><summary type="html">&lt;p&gt;The ICEboard is a fully custom FPGA / ARM motherboard hosting two
high-pin-count (HPC) FPGA Mezzanine (FMC) slots.&lt;/p&gt;
&lt;div class="figure align-center"&gt;
&lt;img alt="ICEBoard, top view" src="/images/iceboard/iceboard_top.jpg" style="width: 100%;" /&gt;
&lt;p class="caption"&gt;The ICEboard, revision 2. The two red mezzanines host high-speed
(gigasample per second) ADCs for the
&lt;a class="reference external" href="http://chime.phas.ubc.ca"&gt;CHIME&lt;/a&gt; experiment. The motherboard
hosts an FPGA and ARM for processing elements, and a variety of
high-speed …&lt;/p&gt;&lt;/div&gt;</summary><content type="html">&lt;p&gt;The ICEboard is a fully custom FPGA / ARM motherboard hosting two
high-pin-count (HPC) FPGA Mezzanine (FMC) slots.&lt;/p&gt;
&lt;div class="figure align-center"&gt;
&lt;img alt="ICEBoard, top view" src="/images/iceboard/iceboard_top.jpg" style="width: 100%;" /&gt;
&lt;p class="caption"&gt;The ICEboard, revision 2. The two red mezzanines host high-speed
(gigasample per second) ADCs for the
&lt;a class="reference external" href="http://chime.phas.ubc.ca"&gt;CHIME&lt;/a&gt; experiment. The motherboard
hosts an FPGA and ARM for processing elements, and a variety of
high-speed interfaces.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Three-Speed Logic collaborated with McGill's Winterland cosmology lab to
design the ICEboard. This board includes:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;A Kintex-7 '420T FPGA (socket-compatible with '325T and '480T variants)&lt;/li&gt;
&lt;li&gt;A TI AM3874 ARM SoC&lt;/li&gt;
&lt;li&gt;&lt;dl class="first docutils"&gt;
&lt;dt&gt;A variety of high-speed serial interfaces:&lt;/dt&gt;
&lt;dd&gt;&lt;ul class="first last"&gt;
&lt;li&gt;Two 10/100/100 Ethernet interfaces&lt;/li&gt;
&lt;li&gt;28 10-Gigabit GTX links&lt;/li&gt;
&lt;/ul&gt;
&lt;/dd&gt;
&lt;/dl&gt;
&lt;/li&gt;
&lt;li&gt;&lt;dl class="first docutils"&gt;
&lt;dt&gt;On-chip storage resources&lt;/dt&gt;
&lt;dd&gt;&lt;ul class="first last"&gt;
&lt;li&gt;SPI flash for bitstream and software storage&lt;/li&gt;
&lt;li&gt;DDR3 SDRAM&lt;/li&gt;
&lt;/ul&gt;
&lt;/dd&gt;
&lt;/dl&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The ICEboard occupies a 9u-height VME slot (340mm high), although cards are
not as deep as a full 9u rack (233mm deep, compared to standard 360mm deep).
Most VME crates are adjustable to accomodate this variation; crate vendors are
also able to ship correctly sized crates.&lt;/p&gt;
&lt;div class="figure align-center"&gt;
&lt;img alt="ICEBoard, top view" src="/images/iceboard/iceboard_perspective.jpg" style="width: 100%;" /&gt;
&lt;p class="caption"&gt;Another view of the ICEboard, without FMC daughtercards. The RF shield
surrounding the ARM CPU has been removed, exposing two DDR3 ICs and
two Ethernet PHYs. The attached programming header is used to
configure the board's two PLLs, which are used to generate system
clocks for the CPU and FPGA.&lt;/p&gt;
&lt;/div&gt;
</content><category term="iceboard"></category></entry></feed>