<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>PRBS23</title>
    <link>https://prbs23.com/blog/</link>
    <description>Recent content on PRBS23</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en-us</language>
    <managingEditor>prbs23@prbs23.com (prbs23)</managingEditor>
    <webMaster>prbs23@prbs23.com (prbs23)</webMaster>
    <lastBuildDate>Thu, 25 May 2023 23:32:04 -0600</lastBuildDate><atom:link href="https://prbs23.com/blog/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Combining Dist Constarints in SystemVerilog</title>
      <link>https://prbs23.com/blog/posts/combining-dist-constraints-in-system-verilog/</link>
      <pubDate>Thu, 25 May 2023 23:32:04 -0600</pubDate>
      <author>prbs23@prbs23.com (prbs23)</author>
      <guid>https://prbs23.com/blog/posts/combining-dist-constraints-in-system-verilog/</guid>
      <description>&lt;h2 id=&#34;basic-distribution-constraints&#34;&gt;Basic Distribution Constraints&lt;/h2&gt;
&lt;p&gt;In SystemVerilog, almost all constraints are some form of boolean expression. The constraint solver&amp;rsquo;s job is to satisfy all these boolean expression when choosing random values. The two exceptions to this are &lt;code&gt;solve before&lt;/code&gt; constraints, which control the order of value resolution, and &lt;code&gt;dist&lt;/code&gt; constraints, witch control the distribution of values chosen. This latter type of constraint is what we are looking at in this post.&lt;/p&gt;
&lt;p&gt;At a high level the distribution constraint provides a syntax for defining the &lt;a href=&#34;https://en.wikipedia.org/wiki/Probability_mass_function&#34;&gt;probability mass function&lt;/a&gt; for a random variable over a given range of discrete values. Below are two examples of &lt;code&gt;dist&lt;/code&gt; constraints and the resulting distribution of values over 100k randomizations. The first specifies linearly increasing probability over four values, while the second shows exponentially increasing probability for the same values.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&#34;text-align:center&#34;&gt;Linear Distribution Function&lt;/th&gt;
&lt;th style=&#34;text-align:center&#34;&gt;Exponential Distribution Function&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&#34;text-align:center&#34;&gt;&lt;figure class=&#34;no-photoswipe&#34;&gt;
  &lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 1
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 2
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 3
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 4
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 5
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 6
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 7
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 8
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 9
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;10
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;11
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;12
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-systemverilog&#34; data-lang=&#34;systemverilog&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;constraint&lt;/span&gt; linear_dist_c {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  value &lt;span style=&#34;color:#66d9ef&#34;&gt;dist&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:/&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:/&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:/&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:/&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:/&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:/&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;6&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;6&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:/&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;7&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;7&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:/&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;8&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
  
&lt;/figure&gt;
&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;&lt;figure class=&#34;no-photoswipe&#34;&gt;
  &lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 1
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 2
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 3
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 4
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 5
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 6
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 7
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 8
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 9
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;10
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;11
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;12
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-systemverilog&#34; data-lang=&#34;systemverilog&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;constraint&lt;/span&gt; linear_dist_c {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  value &lt;span style=&#34;color:#66d9ef&#34;&gt;dist&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:/&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:/&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:/&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:/&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;8&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:/&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;16&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:/&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;32&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;6&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:/&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;64&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;7&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:/&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;128&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
  
&lt;/figure&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&#34;text-align:center&#34;&gt;

&lt;div class=&#34;box &#34; &gt;
  &lt;figure  itemprop=&#34;associatedMedia&#34; itemscope itemtype=&#34;http://schema.org/ImageObject&#34;&gt;
    &lt;div class=&#34;img&#34;&gt;
      &lt;img itemprop=&#34;thumbnail&#34; src=&#34;https://prbs23.com/blog/blog/posts/combining-dist-constraints-in-system-verilog/linear_dist_8.png&#34; alt=&#34;Distribution of values with linear `dist` constraint&#34;/&gt;
      &lt;a href=&#34;https://prbs23.com/blog/blog/posts/combining-dist-constraints-in-system-verilog/linear_dist_8.png&#34; itemprop=&#34;contentUrl&#34;&gt;&lt;/a&gt;
    &lt;/div&gt;
      &lt;figcaption&gt;
          &lt;p&gt;
            Distribution of values with linear `dist` constraint
            
          &lt;/p&gt;
      &lt;/figcaption&gt;
  &lt;/figure&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;

&lt;div class=&#34;box &#34; &gt;
  &lt;figure  itemprop=&#34;associatedMedia&#34; itemscope itemtype=&#34;http://schema.org/ImageObject&#34;&gt;
    &lt;div class=&#34;img&#34;&gt;
      &lt;img itemprop=&#34;thumbnail&#34; src=&#34;https://prbs23.com/blog/blog/posts/combining-dist-constraints-in-system-verilog/exp_dist_8.png&#34; alt=&#34;Distribution of values with exponential `dist` constraint&#34;/&gt;
      &lt;a href=&#34;https://prbs23.com/blog/blog/posts/combining-dist-constraints-in-system-verilog/exp_dist_8.png&#34; itemprop=&#34;contentUrl&#34;&gt;&lt;/a&gt;
    &lt;/div&gt;
      &lt;figcaption&gt;
          &lt;p&gt;
            Distribution of values with exponential `dist` constraint
            
          &lt;/p&gt;
      &lt;/figcaption&gt;
  &lt;/figure&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;In both these cases the probability of the constraint solver choosing a given value is the value&amp;rsquo;s weight divided by the sum of weights. For example the probability of selecting the value 0 in our linear distribution is &lt;code&gt;1/(1+2+...+8) = 1/38 = 0.02631&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Obviously we can make these distributions more complicated, and the language has various syntax variations for specifying distributions. However, the question in this post is what happens if we have multiple different distribution constraints defined for the same variable?&lt;/p&gt;
&lt;h2 id=&#34;applying-multiple-dist-constraints&#34;&gt;Applying Multiple &lt;code&gt;dist&lt;/code&gt; constraints&lt;/h2&gt;
&lt;p&gt;Our first question might be, what does the SystemVerilog LRM say about combinations of distribution constraints? Unfortunately it is completely unspecified. The only real specification about &lt;em&gt;how&lt;/em&gt; constraint solvers should behave with regard to distribution constraints is as follows.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Absent any other constraints, the probability that the expression matches any value in the list is proportional
to its specified weight. If there are constraints on some expressions that cause the distribution weights on
these expressions to be not satisfiable, implementations are only required to satisfy the constraints. An
exception to this rule is a weight of zero, which is treated as a constraint.&lt;/p&gt;
&lt;p&gt;&amp;ndash; IEEE Std 1800-2017 &amp;ldquo;IEEE Standard for SystemVerilog&amp;ndash;Unified Hardware Design, Specification, and Verification Language&amp;rdquo; section 18.5.4&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That&amp;rsquo;s not very helpful. So what happens if we just try it? The figure below shows various combinations of three different distribution constraints, and linear and exponentially increasing distributions from above, along with a uniform distribution where all values are given the same probability. For each combination of distributions I randomized a value 100k times, using three different simulators, to see how various SystemVerilog implementations compared.&lt;/p&gt;


&lt;div class=&#34;box &#34; &gt;
  &lt;figure  itemprop=&#34;associatedMedia&#34; itemscope itemtype=&#34;http://schema.org/ImageObject&#34;&gt;
    &lt;div class=&#34;img&#34;&gt;
      &lt;img itemprop=&#34;thumbnail&#34; src=&#34;https://prbs23.com/blog/blog/posts/combining-dist-constraints-in-system-verilog/simple_dist_combinations.png&#34; alt=&#34;Distribution of values with various combinations of distribution constraints in three simulators.&#34;/&gt;
      &lt;a href=&#34;https://prbs23.com/blog/blog/posts/combining-dist-constraints-in-system-verilog/simple_dist_combinations.png&#34; itemprop=&#34;contentUrl&#34;&gt;&lt;/a&gt;
    &lt;/div&gt;
      &lt;figcaption&gt;
          &lt;p&gt;
            Distribution of values with various combinations of distribution constraints in three simulators.
            
          &lt;/p&gt;
      &lt;/figcaption&gt;
  &lt;/figure&gt;
&lt;/div&gt;

&lt;p&gt;See the following EDAPlayground for how I generated the data these plots: &lt;a href=&#34;https://edaplayground.com/x/wVNy&#34;&gt;Multiple Dist Constraints&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;From this experiment we can see that all three simulators combine the distribution constraints together in some way to create a new distribution (ie. they don&amp;rsquo;t discard the previous dist constraint). However, there appear to be two different methods used, as the combined distributions for Xcelium and VCS are very similar (though maybe not exactly the same), and Questa seems to do something entirely different. Let&amp;rsquo;s see if we can figure out what the tools are doing.&lt;/p&gt;
&lt;h3 id=&#34;combining-distributions-in-xcelium-and-vcs&#34;&gt;Combining Distributions in Xcelium and VCS&lt;/h3&gt;
&lt;p&gt;As far as I could tell, none of the simulators document how they handle combinations of distribution constraints. However, with some experimentation it wasn&amp;rsquo;t hard to come up with a function that appears to behave similarly to Xcelium and VCS. It appears in the case of both Xcelium and VCS, the probability of a given value being selected when there are multiple distribution constraints is simply the average of probabilities from all distribution constraints. Additionally, from the LRM we know that the probability of a given weight for a single &lt;code&gt;dist&lt;/code&gt; constraint is the weight for that value divided by all weights. Therefore, more formally we can say, given &lt;em&gt;N&lt;/em&gt; distribution constraints where the weight for a value &lt;em&gt;x&lt;/em&gt; is given by the function &lt;em&gt;weight&lt;sub&gt;n&lt;/sub&gt;(x)&lt;/em&gt;, the resulting probability mass function is:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;xcelium_vcs_simple_combination_function.svg&#34; alt=&#34;p(x) = \frac{\sum_{n=1}^{N} \frac{weight_n(x)}{\sum_{m=-\infty}^{\infty} weight(m)}}{N}&#34;&gt;&lt;/p&gt;
&lt;p&gt;The figure below shows a comparison of using this formula to compute the expected distributions vs the observed distribution from Xcelium and VCS.&lt;/p&gt;


&lt;div class=&#34;box &#34; &gt;
  &lt;figure  itemprop=&#34;associatedMedia&#34; itemscope itemtype=&#34;http://schema.org/ImageObject&#34;&gt;
    &lt;div class=&#34;img&#34;&gt;
      &lt;img itemprop=&#34;thumbnail&#34; src=&#34;https://prbs23.com/blog/blog/posts/combining-dist-constraints-in-system-verilog/computed_xcelium_vcs_dist.png&#34; alt=&#34;Comparison of Xcelium and VCS distributions to the average of probabilities.&#34;/&gt;
      &lt;a href=&#34;https://prbs23.com/blog/blog/posts/combining-dist-constraints-in-system-verilog/computed_xcelium_vcs_dist.png&#34; itemprop=&#34;contentUrl&#34;&gt;&lt;/a&gt;
    &lt;/div&gt;
      &lt;figcaption&gt;
          &lt;p&gt;
            Comparison of Xcelium and VCS distributions to the average of probabilities.
            
          &lt;/p&gt;
      &lt;/figcaption&gt;
  &lt;/figure&gt;
&lt;/div&gt;

&lt;p&gt;But wait! The SystemVerilog spec says that a weight of zero in a &lt;code&gt;dist&lt;/code&gt; constraint is considered as a hard constraint keeping the variable not equal to the value. If they were just averaging the probabilities together the average of a 0 and non-zero probability is going to be a non-zero value. If we actually test this by running the same experiment with the same sets of constraints, except that the values 1 and 6 are given a weight of 0 in the uniform &lt;code&gt;dist&lt;/code&gt; constraint we get the results in the figure below. Note that the simple average of probabilities doesn&amp;rsquo;t match the actual measured distributions.&lt;/p&gt;


&lt;div class=&#34;box &#34; &gt;
  &lt;figure  itemprop=&#34;associatedMedia&#34; itemscope itemtype=&#34;http://schema.org/ImageObject&#34;&gt;
    &lt;div class=&#34;img&#34;&gt;
      &lt;img itemprop=&#34;thumbnail&#34; src=&#34;https://prbs23.com/blog/blog/posts/combining-dist-constraints-in-system-verilog/computed_xcelium_vcs_partial_dist.png&#34; alt=&#34;Comparison of Xcelium and VCS distributions to the simple average of probabilities and zero-filtered average of probabilities.&#34;/&gt;
      &lt;a href=&#34;https://prbs23.com/blog/blog/posts/combining-dist-constraints-in-system-verilog/computed_xcelium_vcs_partial_dist.png&#34; itemprop=&#34;contentUrl&#34;&gt;&lt;/a&gt;
    &lt;/div&gt;
      &lt;figcaption&gt;
          &lt;p&gt;
            Comparison of Xcelium and VCS distributions to the simple average of probabilities and zero-filtered average of probabilities.
            
          &lt;/p&gt;
      &lt;/figcaption&gt;
  &lt;/figure&gt;
&lt;/div&gt;

&lt;p&gt;We can reproduce the same distribution we observe from Xcelium and VCS with a small modification to the average of probabilities combination technique. The averaging of probabilities appears to function the same, however when computing the probability of selecting a value for each individual distribution constraint, the weight for a value is considered as 0 if &lt;em&gt;any&lt;/em&gt; other &lt;code&gt;dist&lt;/code&gt; constraint has a weight of 0. Therefore a more accurate equation for the final probability mass function for a combination of &lt;em&gt;N&lt;/em&gt; distribution constraints would be:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;xcelium_vcs_zero_filtered_combination_function.svg&#34; alt=&#34;p(x) = \frac{\sum_{n=1}^{N} \frac{weight_n(x) \times (\prod_{i=1}^{N} weight_n(i) &amp;gt; 0)}{\sum_{m=-\infty}^{\infty} (weight(m) \times (\prod_{i=1}^{N} weight_n(i) &amp;gt; 0))}}{N}&#34;&gt;&lt;/p&gt;
&lt;h3 id=&#34;combining-distributions-in-questa&#34;&gt;Combining Distributions in Questa&lt;/h3&gt;
&lt;p&gt;While Xcelium and VCS appear to use a similar function for combining distributions, the Questa simulator does something significantly different. From some experimentation, whatever they are doing appears equivalent to multiplying the weights (not probabilities) from all &lt;code&gt;dist&lt;/code&gt; constraints for each value together, and then computing the probability from these weights. Formally we could write this probability mass function for the combination of N constraints given the weight functions &lt;em&gt;weight&lt;sub&gt;n&lt;/sub&gt;(x)&lt;/em&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;questa_combination_function.svg&#34; alt=&#34;p(x) = \frac{\prod_{n=1}^{N} weight_n(x)}{\sum_{m=-\infty}^{\infty} (\prod_{n=1}^{N} weight_n(x))}&#34;&gt;&lt;/p&gt;
&lt;p&gt;Comparing this probability formulas to the actual results from Questa we get effective the same distributions.&lt;/p&gt;


&lt;div class=&#34;box &#34; &gt;
  &lt;figure  itemprop=&#34;associatedMedia&#34; itemscope itemtype=&#34;http://schema.org/ImageObject&#34;&gt;
    &lt;div class=&#34;img&#34;&gt;
      &lt;img itemprop=&#34;thumbnail&#34; src=&#34;https://prbs23.com/blog/blog/posts/combining-dist-constraints-in-system-verilog/computed_questa_dist.png&#34; alt=&#34;Comparison of Questa distributions to the normalized product of probabilities.&#34;/&gt;
      &lt;a href=&#34;https://prbs23.com/blog/blog/posts/combining-dist-constraints-in-system-verilog/computed_questa_dist.png&#34; itemprop=&#34;contentUrl&#34;&gt;&lt;/a&gt;
    &lt;/div&gt;
      &lt;figcaption&gt;
          &lt;p&gt;
            Comparison of Questa distributions to the normalized product of probabilities.
            
          &lt;/p&gt;
      &lt;/figcaption&gt;
  &lt;/figure&gt;
&lt;/div&gt;

&lt;p&gt;The nice thing about this way of combining distributions is that we get for free that a weight of zero from one constraint will always result in a final probably being 0 as well. If we do a similar test as we did for the other simulators with a partial uniform distribution constraint where some values have a zero probability, we see our formula still matches the results from Questa.&lt;/p&gt;


&lt;div class=&#34;box &#34; &gt;
  &lt;figure  itemprop=&#34;associatedMedia&#34; itemscope itemtype=&#34;http://schema.org/ImageObject&#34;&gt;
    &lt;div class=&#34;img&#34;&gt;
      &lt;img itemprop=&#34;thumbnail&#34; src=&#34;https://prbs23.com/blog/blog/posts/combining-dist-constraints-in-system-verilog/computed_questa_partial_dist.png&#34; alt=&#34;Comparison of Questa distributions to the product of weights.&#34;/&gt;
      &lt;a href=&#34;https://prbs23.com/blog/blog/posts/combining-dist-constraints-in-system-verilog/computed_questa_partial_dist.png&#34; itemprop=&#34;contentUrl&#34;&gt;&lt;/a&gt;
    &lt;/div&gt;
      &lt;figcaption&gt;
          &lt;p&gt;
            Comparison of Questa distributions to the product of weights.
            
          &lt;/p&gt;
      &lt;/figcaption&gt;
  &lt;/figure&gt;
&lt;/div&gt;

&lt;h2 id=&#34;conclusions&#34;&gt;Conclusions&lt;/h2&gt;
&lt;p&gt;While all three simulators do something I would consider reasonable, I&amp;rsquo;m not sure either behavior is necessarily what I would want in any given application. Additionally, since there is no specification defined behavior, there&amp;rsquo;s no guarantees about how your constraint solver will handle any given set of constraints.&lt;/p&gt;
&lt;p&gt;Overall, this investigation has made me wary of ever apply two distribution constraints to the same variable. In general I think I will be putting my distribution constraints inside their own &lt;code&gt;constraint&lt;/code&gt; blocks, so that they can be disabled individually, and replaced, instead of combined with another constraint. It&amp;rsquo;s helpful to now know exactly what a given simulator will do, but I wouldn&amp;rsquo;t rely on it.&lt;/p&gt;
&lt;p&gt;Finally, I have only looked into how multiple distribution constraints interact when applied to a single variable, but there&amp;rsquo;s other questions too&amp;hellip; What if you had two distribution constraints on different variables, but a hard constraint keeping the variables equal? How do distribution constraints interact with other types of hard constraints? One day, maybe I will investigate these too.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Getting Started With a Private LoRaWAN Network</title>
      <link>https://prbs23.com/blog/posts/getting-started-with-a-private-lorawan-network/</link>
      <pubDate>Thu, 07 Jul 2022 22:01:39 -0600</pubDate>
      <author>prbs23@prbs23.com (prbs23)</author>
      <guid>https://prbs23.com/blog/posts/getting-started-with-a-private-lorawan-network/</guid>
      <description>&lt;p&gt;I have recently started experimenting with LoRa radios, and the LoRaWAN network protocol. Interestingly it seems that the LoRa ecosystem is simultaneously surprisingly open (both in specifications and implementations), while also having very little definitive documentation on how to actually get started as an indvidual hacker. As such I found the process of learning enough of the protocol to set up my own network surprisingly difficult.&lt;/p&gt;
&lt;p&gt;This post will walk through the process of setting up my own private LoRaWAN network, from low cost hardware all the way up to the application level. While I would never claim to be an expert in LoRa or LoRaWAN, I hope someone finds this a useful reference.&lt;/p&gt;
&lt;h2 id=&#34;lora-and-lorawan-basics&#34;&gt;LoRa and LoRaWAN Basics&lt;/h2&gt;
&lt;p&gt;LoRa (not to be confused with LoRaWAN) is a proprietary modulation and physical layer standard for low power wireless communication, originally developed in 2010 by Cycleo, which was later acquired by Semtech in 2012. The LoRa physical layer uses a &amp;ldquo;Chirp Spread Spectrum&amp;rdquo; (CSS) modulation technique to spread the signal over either 125, 250, or 500MHz bands. The use of CSS modulation, instead of the more common &amp;ldquo;Direct Sequence Spread Spectrum&amp;rdquo; (DSSS) allows LoRa to transmit over longer ranges and be more robust to many common types of interference.&lt;/p&gt;
&lt;p&gt;The advertised range for LoRa transceivers tend to be in the 1km to 10km range, though from my research it realistically is more often on the lower end of that range. I have not tested what range I can get from my system yet, so I don&amp;rsquo;t have my own empirical data. More information about LoRa modulation and the physical layer can be found in this &lt;a href=&#34;https://semtech--c.na98.content.force.com/sfc/dist/version/download/?oid=00DE0000000JelG&amp;amp;ids=0682R000005PU6SQAW&amp;amp;d=%252Fa%252F2R0000001OJk%252FyDEcfAkD9qEz6oG3PJryoHKas3UMsMDa3TFqz1UQOkM&#34;&gt;Application Note&lt;/a&gt; from Semtech, and this excellent &lt;a href=&#34;http://www.sghoslya.com/&#34;&gt;series of blog posts&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;LoRaWAN, on the other hand, is a &amp;ldquo;Low Power Wide Area Network&amp;rdquo; (LPWAN) specification, built on top of the LoRa physical layer. LoRaWAN defines a network architecture, MAC layer, and link layer protocols, primarily targeted at building low power and bandwidth sensor networks. The LoRaWAN standard is defined by the &lt;a href=&#34;https://lora-alliance.org&#34;&gt;LoRa Alliance&lt;/a&gt;, and is published as an open standard in two primary parts: The &lt;a href=&#34;https://resources.lora-alliance.org/technical-specifications/ts001-1-0-4-lorawan-l2-1-0-4-specification&#34;&gt;LoRaWAN L2 Specification&lt;/a&gt; which defines everything except specific physical layer parameters, and the &lt;a href=&#34;https://resources.lora-alliance.org/technical-specifications/rp2-1-0-3-lorawan-regional-parameters&#34;&gt;LoRaWAN Regional Parameters&lt;/a&gt; which defines physical layer parameters, such as frequency bands, bandwidth, etc. for specific regions of the world, in order to be compliant with local regulations.&lt;/p&gt;


&lt;div class=&#34;box &#34; &gt;
  &lt;figure  itemprop=&#34;associatedMedia&#34; itemscope itemtype=&#34;http://schema.org/ImageObject&#34;&gt;
    &lt;div class=&#34;img&#34;&gt;
      &lt;img itemprop=&#34;thumbnail&#34; src=&#34;https://prbs23.com/blog/blog/posts/getting-started-with-a-private-lorawan-network/lorawan_network_architecture.png&#34; alt=&#34;Basic LoRaWAN Network Architecture.&#34;/&gt;
      &lt;a href=&#34;https://prbs23.com/blog/blog/posts/getting-started-with-a-private-lorawan-network/lorawan_network_architecture.png&#34; itemprop=&#34;contentUrl&#34;&gt;&lt;/a&gt;
    &lt;/div&gt;
      &lt;figcaption&gt;
          &lt;p&gt;
            Basic LoRaWAN Network Architecture.
            
          &lt;/p&gt;
      &lt;/figcaption&gt;
  &lt;/figure&gt;
&lt;/div&gt;

&lt;p&gt;The basic architecture of a LoRaWAN network is shown above. Each LoRaWAN &amp;ldquo;End-Device&amp;rdquo; communicates with one or more &amp;ldquo;Gateway&amp;rdquo; devices over the LoRa physical layer. These gateways forward messages between the end-devices and a &amp;ldquo;Network Server&amp;rdquo; over standard TCP/IP networking. The network server manages all devices connected to one or more gateways, including device activation (joining a network), congestion control, etc. Device authentication is handled by a separate &amp;ldquo;Join Server&amp;rdquo; that interfaces with one or more network servers, and finally any non-management messages from a device are sent from the network server to an application server.&lt;/p&gt;
&lt;h2 id=&#34;getting-started&#34;&gt;Getting Started&lt;/h2&gt;
&lt;p&gt;The simplest way to start using LoRaWAN, is to buy some LoRaWAN devices, connect them to a public network such as &lt;a href=&#34;https://www.thethingsnetwork.org/&#34;&gt;The Things Network&lt;/a&gt;, and you are good to go. While this is simple because all the network and server management is handled by someone else, I wanted to set up my own network. This was partially just to understand how all the pieces of the LoRaWAN network work, but also because I don&amp;rsquo;t have coverage from any of these networks where I live anyway.&lt;/p&gt;
&lt;p&gt;To set up your own network you need essentially four things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;End device hardware, generally a LoRa transceiver and a microcontroller.&lt;/li&gt;
&lt;li&gt;Firmware network stack to run on the end device.&lt;/li&gt;
&lt;li&gt;Gateway radio for the end devices to connect to.&lt;/li&gt;
&lt;li&gt;Gateway client and network/join server software.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;end-devices&#34;&gt;End-Devices&lt;/h3&gt;
&lt;h4 id=&#34;hardware&#34;&gt;Hardware&lt;/h4&gt;
&lt;p&gt;For end-device hardware, there are many different options, from &lt;a href=&#34;https://lora-alliance.org/showcase/search/?_sfm_lorawan_certified_device=certified&amp;amp;_sft_product_categories=end-node-sensors-or-other-devices&#34;&gt;off the shelf LoRaWAN connected sensors and devices&lt;/a&gt;, to bare &lt;a href=&#34;https://www.semtech.com/lora/lora-products&#34;&gt;LoRa transceiver chips&lt;/a&gt;. For my first foray into LoRaWAN I chose to use an integrated LoRa radio/microcontroller module, since I believe it provides the most direct development path to building my own custom device PCBs in the future, while also allowing complete programmability of the device. There are several manufactures that produce these modules with different specifications, but I chose the &lt;a href=&#34;https://www.murata.com/en-us/products/connectivitymodule/lpwa/overview/lineup/type-abz&#34;&gt;CMWX1ZZABZ&lt;/a&gt; module from muRata as it was a fairly common, low cost option.&lt;/p&gt;


&lt;div class=&#34;box &#34; &gt;
  &lt;figure  itemprop=&#34;associatedMedia&#34; itemscope itemtype=&#34;http://schema.org/ImageObject&#34;&gt;
    &lt;div class=&#34;img&#34;&gt;
      &lt;img itemprop=&#34;thumbnail&#34; src=&#34;https://prbs23.com/blog/blog/posts/getting-started-with-a-private-lorawan-network/b-l072z-lrwan1_development_board.png&#34; alt=&#34;B-L072Z-LRWAN1 board for CMWX1ZZABZ module used as end-device for testing network.&#34;/&gt;
      &lt;a href=&#34;https://prbs23.com/blog/blog/posts/getting-started-with-a-private-lorawan-network/b-l072z-lrwan1_development_board.png&#34; itemprop=&#34;contentUrl&#34;&gt;&lt;/a&gt;
    &lt;/div&gt;
      &lt;figcaption&gt;
          &lt;p&gt;
            B-L072Z-LRWAN1 board for CMWX1ZZABZ module used as end-device for testing network.
            
          &lt;/p&gt;
      &lt;/figcaption&gt;
  &lt;/figure&gt;
&lt;/div&gt;

&lt;p&gt;The CMWX1ZZABZ module integrates a Semtech SX1276 LoRa transceiver, RF switch, and STM32L microcontroller into single surface mount RF module that is easily integrated onto a custom PCB. The integration of a STM32 MCU is convenient, as this is a microcontroller platform that I am already familiar with. Additionally, ST Microelectronics even sells the &lt;a href=&#34;https://www.st.com/en/evaluation-tools/b-l072z-lrwan1.html&#34;&gt;B-L072Z-LRWAN1&lt;/a&gt; development board that included everything I needed to get started building a LoRaWAN end-device.&lt;/p&gt;
&lt;h4 id=&#34;firmware-networking-stack&#34;&gt;Firmware Networking Stack&lt;/h4&gt;
&lt;p&gt;In addition to the end-device hardware, I also needed firmware that implemented the end-device side of the LoRaWAN protocol. Fortunately, Semtech have published a BSD licensed &lt;a href=&#34;https://github.com/Lora-net/LoRaMac-node&#34;&gt;LoRaWAN end-device networking stack&lt;/a&gt; that works with many of their LoRa transceiver chips. Even better, STMicroelectronics, provide a &lt;a href=&#34;https://www.st.com/en/embedded-software/i-cube-lrwan.html&#34;&gt;packaged version of this library&lt;/a&gt; that is already integrated with their STM32Cube embedded software stack. This makes it very simple to get some demo applications running on the B-L072Z-LRWAN1 development board with very little effort.&lt;/p&gt;
&lt;p&gt;One of the demo applications provided as part of the STM32Cube LoRaWAN expansion makes the module behave as a &lt;a href=&#34;https://www.st.com/resource/en/application_note/an4967-examples-of-at-commands-on-icubelrwan-stmicroelectronics.pdf&#34;&gt;fully featured LoRaWAN modem that accepts AT style commands&lt;/a&gt; over a UART port. This AT modem application firmware is what I ended up using to test and debug, as it gave me interactive control over my end-device with known working firmware, so I didn&amp;rsquo;t need to debug my own firmware at the same time as my network configuration.&lt;/p&gt;
&lt;h3 id=&#34;gateway&#34;&gt;Gateway&lt;/h3&gt;
&lt;h4 id=&#34;hardware-1&#34;&gt;Hardware&lt;/h4&gt;
&lt;p&gt;Unlike the end-devices, the hardware for a Gateway turns out to be a bit more complicated. Primarily this is because while the end-device only needs to transmit or receive on one channel at a time, gateways generally must be able to receive packets from multiple end-devices on multiple channels simultaneously&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;. Additionally, not only must the gateway be able to receive packets on typically several channels at once, in order to support the class B beacon protocol the gateway must use &lt;a href=&#34;https://content.cdntwrk.com/files/aT0xNDI4Mzk1JnY9MSZpc3N1ZU5hbWU9dHMwMDEtMS0wLTQtbG9yYXdhbi1sMi0xLTAtNC1zcGVjaWZpY2F0aW9uJmNtZD1kJnNpZz0xYWMyYjRiZjM3YTExNWMzZDU2NzBiYTM4OTAyY2E5ZA%253D%253D#%5B%7B%22num%22%3A166%2C%22gen%22%3A0%7D%2C%7B%22name%22%3A%22XYZ%22%7D%2C69%2C733%2C0%5D&#34;&gt;GPS to get precise time and location information&lt;/a&gt;, and also has to have a full TCP/IP networking stack to communicate with the network server.&lt;/p&gt;
&lt;p&gt;Now, there &lt;a href=&#34;https://lora-alliance.org/showcase/search/?_sft_product_categories=gateway&#34;&gt;&lt;em&gt;are&lt;/em&gt; full off the shelf LoRaWAN gateways for sale&lt;/a&gt;, but most don&amp;rsquo;t even publish a price, and as the adage goes &amp;ldquo;if you have to ask the price you can&amp;rsquo;t afford it&amp;rdquo;. Even the few gateway devices that you can easily purchase are usually north of $400, which was a little out of &lt;em&gt;my&lt;/em&gt; budget. After some research, it turns out that most LoRaWAN gateways are built off the same Semtech SX130x (baseband)/SX125x (front-end) chipset, connected to something like a fairly beefy ARM processor running Linux. The general structure of one of these gateways is shown in the block diagram below, from the Semtech LoRaWAN gateway &amp;ldquo;Corecell&amp;rdquo; reference design.&lt;/p&gt;


&lt;div class=&#34;box &#34; &gt;
  &lt;figure  itemprop=&#34;associatedMedia&#34; itemscope itemtype=&#34;http://schema.org/ImageObject&#34;&gt;
    &lt;div class=&#34;img&#34;&gt;
      &lt;img itemprop=&#34;thumbnail&#34; src=&#34;https://prbs23.com/blog/blog/posts/getting-started-with-a-private-lorawan-network/lorawan_corecell_block_diagram.png&#34; alt=&#34;Semtech Block Diagram of &amp;#34;Corecell&amp;#34; gateway reference design&#34;/&gt;
      &lt;a href=&#34;https://prbs23.com/blog/blog/posts/getting-started-with-a-private-lorawan-network/lorawan_corecell_block_diagram.png&#34; itemprop=&#34;contentUrl&#34;&gt;&lt;/a&gt;
    &lt;/div&gt;
      &lt;figcaption&gt;
          &lt;p&gt;
            Semtech Block Diagram of &amp;#34;Corecell&amp;#34; gateway reference design
             (&lt;a href=&#34;https://semtech--c.na98.content.force.com/sfc/dist/version/download/?oid=00DE0000000JelG&amp;amp;ids=0682R000006GEO0QAO&amp;amp;d=%2Fa%2F2R000000HV3G%2Fan5Oh4KfiY7tAO1MO7RiPOj08WUpOTjPHSF57_.NlJ0&amp;amp;operationContext=DELIVERY&amp;amp;asPdf=true&amp;amp;viewId=05H2R000002Z67aUAC&amp;amp;dpt=#page=6&#34;&gt;Semtech Corecell Reference Design Users Guide&lt;/a&gt;)
          &lt;/p&gt;
      &lt;/figcaption&gt;
  &lt;/figure&gt;
&lt;/div&gt;

&lt;p&gt;Since I was trying to avoid spending hundreds of dollars if I could, I did briefly consider building my own gateway PCB based on this architecture. However due to the ongoing &amp;ldquo;Chipageddon&amp;rdquo;, I couldn&amp;rsquo;t actually get my hands on bare SX1308 chips. In the end I found that the &lt;a href=&#34;https://pycom.io/&#34;&gt;Pycom&lt;/a&gt; makes an expansion board for their &lt;a href=&#34;https://docs.pycom.io/datasheets/development/wipy3/&#34;&gt;Wipy microcontroller modules&lt;/a&gt; that turns them into a LoRaWAN gateway. Now, I wasn&amp;rsquo;t interested in actually using a Wipy or their associated software, but the &lt;a href=&#34;https://docs.pycom.io/datasheets/expansionboards/pygate/&#34;&gt;&amp;ldquo;Pygate&amp;rdquo; expansion module&lt;/a&gt; is essentially a copy of the Semtech reference design above that I could pick one up for &lt;a href=&#34;https://www.digikey.com/en/products/detail/pycom-ltd/604565285973/12354323&#34;&gt;$52 from Mouser&lt;/a&gt;.&lt;/p&gt;


&lt;div class=&#34;box &#34; &gt;
  &lt;figure  itemprop=&#34;associatedMedia&#34; itemscope itemtype=&#34;http://schema.org/ImageObject&#34;&gt;
    &lt;div class=&#34;img&#34;&gt;
      &lt;img itemprop=&#34;thumbnail&#34; src=&#34;https://prbs23.com/blog/blog/posts/getting-started-with-a-private-lorawan-network/lorawan_basestation_wiring.png&#34; alt=&#34;Connections between Raspberry PI, Pygate module, and GPS.&#34;/&gt;
      &lt;a href=&#34;https://prbs23.com/blog/blog/posts/getting-started-with-a-private-lorawan-network/lorawan_basestation_wiring.png&#34; itemprop=&#34;contentUrl&#34;&gt;&lt;/a&gt;
    &lt;/div&gt;
      &lt;figcaption&gt;
          &lt;p&gt;
            Connections between Raspberry PI, Pygate module, and GPS.
            
          &lt;/p&gt;
      &lt;/figcaption&gt;
  &lt;/figure&gt;
&lt;/div&gt;

&lt;p&gt;To make a full gateway device, I connected the Pygate module to an old Raspberry Pi (Model B rev. 2) and a &lt;a href=&#34;https://www.sparkfun.com/products/13670&#34;&gt;GP-736&lt;/a&gt; GPS module that I had laying around. The GPS module unfortunately does not have a 1pps output that can be used for very precise timing. But even it&amp;rsquo;s limitations this it is sufficient to build an equivalent system to the Corecell reference design, and more importantly, works with the Basic Station software from Semtech.&lt;/p&gt;


&lt;div class=&#34;box &#34; &gt;
  &lt;figure  itemprop=&#34;associatedMedia&#34; itemscope itemtype=&#34;http://schema.org/ImageObject&#34;&gt;
    &lt;div class=&#34;img&#34;&gt;
      &lt;img itemprop=&#34;thumbnail&#34; src=&#34;https://prbs23.com/blog/blog/posts/getting-started-with-a-private-lorawan-network/lorawan_basestation_system.png&#34; alt=&#34;Hardware setup for my low cost LoRaWAN gateway.&#34;/&gt;
      &lt;a href=&#34;https://prbs23.com/blog/blog/posts/getting-started-with-a-private-lorawan-network/lorawan_basestation_system.png&#34; itemprop=&#34;contentUrl&#34;&gt;&lt;/a&gt;
    &lt;/div&gt;
      &lt;figcaption&gt;
          &lt;p&gt;
            Hardware setup for my low cost LoRaWAN gateway.
            
          &lt;/p&gt;
      &lt;/figcaption&gt;
  &lt;/figure&gt;
&lt;/div&gt;

&lt;h4 id=&#34;gateway-software&#34;&gt;Gateway Software&lt;/h4&gt;
&lt;p&gt;To go along with Semtech&amp;rsquo;s Corecell reference design, they also provide the source for an packet forwarder application they call &lt;a href=&#34;https://github.com/lorabasics/basicstation&#34;&gt;LoRa Basics Station&lt;/a&gt;. This software contains the code to drive the SX1308 and SX1257 chips on the Pygate board, and read timing and location information from a standard NEMA GPS data stream and. This application connects a LoRa network server to forward packets between end devices and the LoRaWAN network.&lt;/p&gt;
&lt;p&gt;Building the Basics Station software turned out to be fairly straight forward. In fact Semtech have already put in the hard work to get it building on Raspberry Pi, so it&amp;rsquo;s as simple as:&lt;/p&gt;
&lt;figure class=&#34;no-photoswipe&#34;&gt;
  &lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;1
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;2
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;git clone https://github.com/lorabasics/basicstation.git basicstation
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cd basicstation
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;make platform&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;rpi variant&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;std
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
  
&lt;/figure&gt;

&lt;p&gt;We will get into configuring and running the software a bit later, as that turned out to be the tricky bit, and requires some understanding of the rest of the network servers.&lt;/p&gt;
&lt;p&gt;While the Basic Station software was already set up to drive the whole SX1308/SX1257 chipset at runtime, it didn&amp;rsquo;t handle everything for me. Specifically, the Pygate board has four input pins that must be driven correctly by the Raspberry Pi before it will work:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;RFPWR_EN:&lt;/strong&gt; Enable signal to voltage regulator for RF power rail. Needs to be driven high to power RF front-end.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;FEM_EN&lt;/strong&gt;: Enable signal to RF front-end. Must be driven high before enable front end circuits.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SX1308_RST:&lt;/strong&gt; Active high reset for SX1308 chip. Can be driven high to reset SX1308 chip, must be low at runtime.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SX1257_RST:&lt;/strong&gt; Active high reset for both SX1257 chip. Can be driven high to reset the SX1257 chips, must be low during operation.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;While these possibly could have been tied high and low respectively, I connected these signals to Raspberry Pi GPIO pins and used the following shell script to power up the Pygate board and bring the chips out of reset:&lt;/p&gt;
&lt;figure class=&#34;no-photoswipe&#34; style=&#34;--max-figure-height:300px;&#34;&gt;
  &lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 1
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 2
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 3
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 4
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 5
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 6
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 7
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 8
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 9
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;10
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;11
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;12
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;13
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;14
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;15
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;16
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;17
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;18
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;19
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;20
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;21
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;22
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;23
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;24
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;25
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;26
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;27
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;28
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#!/bin/sh
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sx1308_rst&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;22&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sx1257_rst&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;27&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;fem_en&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;17&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;rfpwr_en&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Export IOs&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;$sx1308_rst&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt; &amp;gt; /sys/class/gpio/export; sleep 0.1;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;$sx1257_rst&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt; &amp;gt; /sys/class/gpio/export; sleep 0.1;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;$fem_en&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;     &amp;gt; /sys/class/gpio/export; sleep 0.1;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;$rfpwr_en&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;   &amp;gt; /sys/class/gpio/export; sleep 0.1;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Make IOs outputs&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;out&amp;#34;&lt;/span&gt; &amp;gt; /sys/class/gpio/gpio$sx1308_rst/direction; sleep 0.1;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;out&amp;#34;&lt;/span&gt; &amp;gt; /sys/class/gpio/gpio$sx1257_rst/direction; sleep 0.1;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;out&amp;#34;&lt;/span&gt; &amp;gt; /sys/class/gpio/gpio$rfpwr_en/direction;   sleep 0.1;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;out&amp;#34;&lt;/span&gt; &amp;gt; /sys/class/gpio/gpio$fem_en/direction;     sleep 0.1;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Enable power rails and assert resets&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;1&amp;#34;&lt;/span&gt; &amp;gt; /sys/class/gpio/gpio$sx1308_rst/value; sleep 0.1;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;1&amp;#34;&lt;/span&gt; &amp;gt; /sys/class/gpio/gpio$sx1257_rst/value; sleep 0.1;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;1&amp;#34;&lt;/span&gt; &amp;gt; /sys/class/gpio/gpio$rfpwr_en/value;   sleep 0.1;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;1&amp;#34;&lt;/span&gt; &amp;gt; /sys/class/gpio/gpio$fem_en/value;     sleep 0.1;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Deassert resets&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;0&amp;#34;&lt;/span&gt; &amp;gt; /sys/class/gpio/gpio$sx1308_rst/value; sleep 0.1;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;0&amp;#34;&lt;/span&gt; &amp;gt; /sys/class/gpio/gpio$sx1257_rst/value; sleep 0.1;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
  
    &lt;figcaption&gt;&lt;span&gt;pygate_setup.sh&lt;/span&gt;&lt;/figcaption&gt;
  
&lt;/figure&gt;

&lt;p&gt;One advantage of driving these enables/resets from GPIOs is that I can also reset or power down the whole LoRa chipset remotely using another shell script:&lt;/p&gt;
&lt;figure class=&#34;no-photoswipe&#34; style=&#34;--max-figure-height:300px;&#34;&gt;
  &lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 1
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 2
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 3
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 4
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 5
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 6
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 7
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 8
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 9
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;10
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;11
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;12
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;13
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;14
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#!/bin/sh
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sx1308_rst&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;22&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sx1257_rst&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;27&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;fem_en&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;17&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;rfpwr_en&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Assert resets&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;1&amp;#34;&lt;/span&gt; &amp;gt; /sys/class/gpio/gpio$sx1308_rst/value; sleep 0.1;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;1&amp;#34;&lt;/span&gt; &amp;gt; /sys/class/gpio/gpio$sx1257_rst/value; sleep 0.1;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Disable power rails&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;0&amp;#34;&lt;/span&gt; &amp;gt; /sys/class/gpio/gpio$fem_en/value;     sleep 0.1;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;0&amp;#34;&lt;/span&gt; &amp;gt; /sys/class/gpio/gpio$rfpwr_en/value;   sleep 0.1;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
  
    &lt;figcaption&gt;&lt;span&gt;pygate_shutdown.sh&lt;/span&gt;&lt;/figcaption&gt;
  
&lt;/figure&gt;

&lt;h3 id=&#34;servers&#34;&gt;Servers&lt;/h3&gt;
&lt;p&gt;With the network hardware figured out, I just just needed the core LoRaWAN servers and an application back-end to send data to. For the LoRaWAN core servers ended up choosing to use &lt;a href=&#34;https://www.chirpstack.io/&#34;&gt;ChirpStack&lt;/a&gt;. It provides an integrated solution for the full LoRaWAN network core that is simple to self-host, has many back-end integrations out of the box, and is open source. For my back-end application I&amp;rsquo;m starting with logging messages to an InfluxDB time series database.&lt;/p&gt;
&lt;p&gt;All the details of the ChirpStack architecture, can be found in their &lt;a href=&#34;https://www.chirpstack.io/project/architecture/&#34;&gt;architecture documentation&lt;/a&gt;. Depending on the size of the network, and applications being run over it, ChirpStack can be deployed in different ways, but for my initial setup, this is what I architecture ended up landing on:&lt;/p&gt;


&lt;div class=&#34;box &#34; &gt;
  &lt;figure  itemprop=&#34;associatedMedia&#34; itemscope itemtype=&#34;http://schema.org/ImageObject&#34;&gt;
    &lt;div class=&#34;img&#34;&gt;
      &lt;img itemprop=&#34;thumbnail&#34; src=&#34;https://prbs23.com/blog/blog/posts/getting-started-with-a-private-lorawan-network/chirpstack_deployment.png&#34; alt=&#34;ChirpStack server deployment.&#34;/&gt;
      &lt;a href=&#34;https://prbs23.com/blog/blog/posts/getting-started-with-a-private-lorawan-network/chirpstack_deployment.png&#34; itemprop=&#34;contentUrl&#34;&gt;&lt;/a&gt;
    &lt;/div&gt;
      &lt;figcaption&gt;
          &lt;p&gt;
            ChirpStack server deployment.
            
          &lt;/p&gt;
      &lt;/figcaption&gt;
  &lt;/figure&gt;
&lt;/div&gt;

&lt;h4 id=&#34;chirpstack-on-the-gateway&#34;&gt;ChirpStack On the Gateway&lt;/h4&gt;
&lt;p&gt;To connect the Semtech Basic Station packet forwarder into the ChirpStack infrastructure we need to use the ChirpStack Gateway Bridge. This acts as a shim between the Semtech LNS protocol used by the Basic Station packet forwarder and the MQTT protocol and API used by ChirpStack&lt;sup id=&#34;fnref:2&#34;&gt;&lt;a href=&#34;#fn:2&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;. We have the choice of running the Gateway Bridge either on the Raspberry Pi gateway or on the server with the ChirpStack Network Server, I chose to run it on the Raspberry Pi so that all the external network communication would be happening within the domain of ChirpStack protocols.&lt;/p&gt;
&lt;p&gt;Unlike the other ChirpStack components I ended up needing to build the gateway bridge from source, this was because my Raspberry Pi board was old enough that the CPU was not supported by the pre-built ARM binaries. Fortunately this is not too difficult, I just needed to install the Go compiler and run make:&lt;/p&gt;
&lt;figure class=&#34;no-photoswipe&#34;&gt;
  &lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;1
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;2
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;3
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;4
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apt-get intall golang-go
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;git clone https://github.com/brocaar/chirpstack-gateway-bridge.git chirpstack-gateway-bridge
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cd chirpstack-gateway-bridge
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;make build
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
  
&lt;/figure&gt;

&lt;h4 id=&#34;chirpstack-in-docker-compose&#34;&gt;ChirpStack in Docker Compose&lt;/h4&gt;
&lt;p&gt;The rest of the chirpstack components and my back-end database I am running on a standard x86 computer running linux as docker containers, managed with docker-compose. ChirpStack conveniently publishes an example docker-compose configuration on this GitHub page: &lt;a href=&#34;https://github.com/brocaar/chirpstack-docker&#34;&gt;brocaar/chirpstack-docker&lt;/a&gt;. This gave me a good starting place but the configuration did not match the server setup I was looking for, and did not include my back-end InfluxDB database. My final docker-compose and other configurations can be found in the &lt;a href=&#34;https://gitlab.com/prbs23/chirpstack-docker&#34;&gt;prbs23/chirpstack-docker GitLab repository&lt;/a&gt;.&lt;/p&gt;
&lt;figure class=&#34;no-photoswipe&#34; style=&#34;--max-figure-height:400px;&#34;&gt;
  &lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 1
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 2
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 3
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 4
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 5
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 6
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 7
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 8
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 9
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;10
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;11
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;12
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;13
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;14
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;15
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;16
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;17
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;18
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;19
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;20
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;21
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;22
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;23
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;24
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;25
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;26
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;27
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;28
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;29
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;30
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;31
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;32
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;33
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;34
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;35
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;36
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;37
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;38
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;39
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;40
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;41
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;42
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;43
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;44
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;45
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;46
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;47
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;48
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;49
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;50
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;51
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;52
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;53
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;54
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;55
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;56
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;57
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;58
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;59
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;60
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;61
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;62
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;63
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;64
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;65
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;version&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;3&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;services&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;chirpstack-network-server&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;image&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;chirpstack/chirpstack-network-server:3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;volumes&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#ae81ff&#34;&gt;./configuration/chirpstack-network-server:/etc/chirpstack-network-server&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;depends_on&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#ae81ff&#34;&gt;postgresql&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#ae81ff&#34;&gt;mosquitto&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;chirpstack-application-server&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;image&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;chirpstack/chirpstack-application-server:3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;ports&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#ae81ff&#34;&gt;7070&lt;/span&gt;:&lt;span style=&#34;color:#ae81ff&#34;&gt;7070&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;volumes&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#ae81ff&#34;&gt;./configuration/chirpstack-application-server:/etc/chirpstack-application-server&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;depends_on&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#ae81ff&#34;&gt;chirpstack-network-server&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;postgresql&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;image&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;postgres:9.6-alpine&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;environment&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#ae81ff&#34;&gt;POSTGRES_PASSWORD=&amp;lt;POSTGRESS_ROOT_PASSWORD&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;volumes&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#ae81ff&#34;&gt;./configuration/postgresql/initdb:/docker-entrypoint-initdb.d&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#ae81ff&#34;&gt;postgresqldata:/var/lib/postgresql/data&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;redis&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;image&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;redis:5-alpine&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;volumes&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#ae81ff&#34;&gt;redisdata:/data&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;mosquitto&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;image&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;eclipse-mosquitto:2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;ports&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#ae81ff&#34;&gt;7072&lt;/span&gt;:&lt;span style=&#34;color:#ae81ff&#34;&gt;7072&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;volumes&lt;/span&gt;: 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#ae81ff&#34;&gt;./configuration/eclipse-mosquitto/mosquitto.conf:/mosquitto/config/mosquitto.conf&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;influxdb&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;image&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;influxdb:latest&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;volumes&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#75715e&#34;&gt;# Mount for influxdb data directory and configuration&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#ae81ff&#34;&gt;./influxdb2:/var/lib/influxdb2:rw&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;ports&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;7074:8086&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;grafana&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;image&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;grafana/grafana-oss:latest&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;ports&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;7075:3000&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;volumes&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#ae81ff&#34;&gt;grafana-storage:/var/lib/grafana&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#ae81ff&#34;&gt;./grafana-provisioning/:/etc/grafana/provisioning&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;depends_on&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#ae81ff&#34;&gt;influxdb&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;environment&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#ae81ff&#34;&gt;GF_SECURITY_ADMIN_USER=admin&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#ae81ff&#34;&gt;GF_SECURITY_ADMIN_PASSWORD=&amp;lt;GRAFANA_ADMIN_PASSWORD&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;volumes&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;postgresqldata&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;redisdata&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;grafana-storage&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
  
    &lt;figcaption&gt;&lt;span&gt;docker-compose.yml&lt;/span&gt;&lt;/figcaption&gt;
  
&lt;/figure&gt;

&lt;p&gt;There are a couple main things that I customized from ChirpStack&amp;rsquo;s default docker-compose file:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Removed the ChirpStack Gateway Bridge container, because I am running the gateway bridge on my gateway device itself.&lt;/li&gt;
&lt;li&gt;Changed the external facing ports. I have other applications running on this server that already used the default ports.&lt;/li&gt;
&lt;li&gt;Added InfluxDB time series database and Grafana containers to the configuration. Because my first application for this network will be data logging, I&amp;rsquo;m using the InfluxDB integration with ChirpStack as an easy time series data store, and Grafana to plot the collected data.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;configuring-the-network&#34;&gt;Configuring the Network&lt;/h2&gt;
&lt;p&gt;Now that I have all the hardware and software pieces I need for a private LoRaWAN network, I just needed to configure them to work together. This turned out to be more complicated than I expected, and also poorly documented, so I&amp;rsquo;ll walk through the important configurations for each component in the system.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The following configuration is set up as a test network. There are multiple authentication and security features available in ChirpStack which I have not configured for this application, but you should be using for a real network.&lt;/p&gt;
&lt;h3 id=&#34;network-server&#34;&gt;Network Server&lt;/h3&gt;
&lt;figure class=&#34;no-photoswipe&#34; style=&#34;--max-figure-height:200px;&#34;&gt;
  &lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 1
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 2
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 3
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 4
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 5
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 6
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 7
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 8
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 9
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;10
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;11
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;12
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;13
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;14
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;15
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;16
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;17
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;18
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;19
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;20
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-toml&#34; data-lang=&#34;toml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;postgresql&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;dsn&lt;/span&gt;=&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;postgres://chirpstack_ns:&amp;lt;POSTGRES_NS_PASSWORD&amp;gt;@postgresql/chirpstack_ns?sslmode=disable&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;redis&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;url&lt;/span&gt;=&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;redis://redis:6379&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;network_server&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;net_id&lt;/span&gt;=&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;000000&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;network_server&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;band&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;name&lt;/span&gt;=&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;US915&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  [&lt;span style=&#34;color:#a6e22e&#34;&gt;network_server&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;network_settings&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;enabled_uplink_channels&lt;/span&gt;=[&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;6&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;7&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;64&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;network_server&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;gateway&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;backend&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;mqtt&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;server&lt;/span&gt;=&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;tcp://mosquitto:7072&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;join_server&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;default&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;server&lt;/span&gt;=&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;http://chirpstack-application-server:8003&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
  
    &lt;figcaption&gt;&lt;span&gt;chirpstack-network-server.toml&lt;/span&gt;&lt;/figcaption&gt;
  
&lt;/figure&gt;

&lt;p&gt;The network server configuration is located in a file named by default &lt;code&gt;chirpstack-network-server.toml&lt;/code&gt;, and primarily configures the connectivity and credentials between the network server and the other components in the ChirpStack architecture. There are however a couple interesting LoRaWAN setting to call out.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;net_id&lt;/code&gt;: Specifies the LoRaWAN network ID for the network server. The network ID is used to uniquely identify LoRaWAN networks when routing between network servers when supporting network roaming. If you wanted to support connecting end devices through other device&amp;rsquo;s gateways, then it is necessary to acquire a unique network ID from the LoRa Alliance. However, network IDs &lt;code&gt;0x000000&lt;/code&gt; and &lt;code&gt;0x000001&lt;/code&gt; are reserved for experimental networks (I consider this experimental), and networks that are not using roaming (which I am not), so this can just be set to &lt;code&gt;0x000000&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;band&lt;/code&gt;: Defines which region from the LoRaWAN Regional Parameters specification is being used for this network. Since my network is located in the US, I have to use &amp;ldquo;US915&amp;rdquo; as my band.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;enabled_uplink_channels&lt;/code&gt;: Declares the subset of channels (as defined by the regional parameters specification for the US915 band) are to be used on the network. For reasons we will get into later, only a subset of 9 channels will be enabled.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;application-server&#34;&gt;Application Server&lt;/h3&gt;
&lt;figure class=&#34;no-photoswipe&#34; style=&#34;--max-figure-height:200px;&#34;&gt;
  &lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 1
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 2
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 3
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 4
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 5
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 6
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 7
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 8
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 9
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;10
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;11
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;12
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;13
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;14
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;15
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-toml&#34; data-lang=&#34;toml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;postgresql&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;dsn&lt;/span&gt;=&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;postgres://chirpstack_as:&amp;lt;POSTGRES_AS_PASSWORD&amp;gt;@postgresql/chirpstack_as?sslmode=disable&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;redis&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;url&lt;/span&gt;=&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;redis://redis:6379&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;application_server&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;integration&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;mqtt&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;server&lt;/span&gt;=&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;tcp://mosquitto:7072&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;application_server&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;api&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;public_host&lt;/span&gt;=&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;chirpstack-application-server:8001&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;application_server&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;external_api&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;bind&lt;/span&gt;=&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;0.0.0.0:7070&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;jwt_secret&lt;/span&gt;=&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;lt;JWT_SECRET&amp;gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
  
    &lt;figcaption&gt;&lt;span&gt;chirpstack-application-server.toml&lt;/span&gt;&lt;/figcaption&gt;
  
&lt;/figure&gt;

&lt;p&gt;Since the application server is not directly interfacing with the LoRaWAN network, the configuration here is pretty simple. Really it just needs to configure the connections between it and the databases and MQTT server docker containers.&lt;/p&gt;
&lt;h3 id=&#34;gateway-bridge&#34;&gt;Gateway Bridge&lt;/h3&gt;
&lt;figure class=&#34;no-photoswipe&#34; style=&#34;--max-figure-height:200px;&#34;&gt;
  &lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 1
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 2
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 3
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 4
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 5
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 6
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 7
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 8
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 9
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;10
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;11
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;12
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;13
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;14
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;15
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;16
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;17
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;18
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;19
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;20
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;21
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;22
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;23
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;24
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;25
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;26
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;27
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;28
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;29
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;30
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;31
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;32
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-toml&#34; data-lang=&#34;toml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Gateway backend configuration.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;backend&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;type&lt;/span&gt;=&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;basic_station&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;# Basic Station backend.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  [&lt;span style=&#34;color:#a6e22e&#34;&gt;backend&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;basic_station&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;bind&lt;/span&gt;=&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;localhost:3001&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;# Channel Configuration&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;region&lt;/span&gt;=&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;US915&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;frequency_min&lt;/span&gt;=&lt;span style=&#34;color:#ae81ff&#34;&gt;902000000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;frequency_max&lt;/span&gt;=&lt;span style=&#34;color:#ae81ff&#34;&gt;928000000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  [[&lt;span style=&#34;color:#a6e22e&#34;&gt;backend&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;basic_station&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;concentrators&lt;/span&gt;]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    [&lt;span style=&#34;color:#a6e22e&#34;&gt;backend&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;basic_station&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;concentrators&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;multi_sf&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;frequencies&lt;/span&gt;=[
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#ae81ff&#34;&gt;902300000&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	    &lt;span style=&#34;color:#ae81ff&#34;&gt;902500000&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	    &lt;span style=&#34;color:#ae81ff&#34;&gt;902700000&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	    &lt;span style=&#34;color:#ae81ff&#34;&gt;902900000&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	    &lt;span style=&#34;color:#ae81ff&#34;&gt;903100000&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	    &lt;span style=&#34;color:#ae81ff&#34;&gt;903300000&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	    &lt;span style=&#34;color:#ae81ff&#34;&gt;903500000&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	    &lt;span style=&#34;color:#ae81ff&#34;&gt;903700000&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    [&lt;span style=&#34;color:#a6e22e&#34;&gt;backend&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;basic_station&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;concentrators&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;lora_std&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;frequency&lt;/span&gt;=&lt;span style=&#34;color:#ae81ff&#34;&gt;903000000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;bandwidth&lt;/span&gt;=&lt;span style=&#34;color:#ae81ff&#34;&gt;500000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;spreading_factor&lt;/span&gt;=&lt;span style=&#34;color:#ae81ff&#34;&gt;8&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Network server configuration.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;integration&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;mqtt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;auth&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;generic&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;servers&lt;/span&gt;=[&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;tcp://&amp;lt;network_server_host&amp;gt;:7072&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
  
    &lt;figcaption&gt;&lt;span&gt;chirpstack-gateway-bridge.toml&lt;/span&gt;&lt;/figcaption&gt;
  
&lt;/figure&gt;

&lt;p&gt;In addition to setting up hosts and ports for the connections to the network server and packet forwarding application, this configuration is where we define the receive channels that will be used by the gateway. To understand how these settings should be configured we need to understand two things:&lt;/p&gt;
&lt;p&gt;First, we need to know how the regional parameters specification defines the LoRaWAN channels for our region. In my case the &lt;a href=&#34;https://content.cdntwrk.com/files/aT0xNDI4MzI2JnY9MSZpc3N1ZU5hbWU9cnAyLTEtMC0zLWxvcmF3YW4tcmVnaW9uYWwtcGFyYW1ldGVycyZjbWQ9ZCZzaWc9ZDI4NDMxYzU2NTVjZjZjZDRiYzJiM2ExZGEwMTAzMmM%253D#page=30&#34;&gt;US915 LoRaWAN Regional Parameters&lt;/a&gt; specification defines 72 uplink channels. The first 64 channels are defined as 125khz wide channels spaced every 200khz starting 902.3Mhz. The remaining 8 channels are 500khz wide spaced every 1.6Mhz starting at 902.3Mhz&lt;/p&gt;
&lt;p&gt;The second thing to understand what is supported by the SX1308 radio baseband chip. The SX1308 has 10 independent receive demodulation data paths that operate in parallel. Channels 0-7 are fixed 125khz LoRa demodulators with independently controlled frequencies, which can demodulate all LoRa spreading factors simultaneously. Channel 8 has a configurable LoRa demodulator that supports 125khz, 250khz, and 500khz channel bandwidth and a configurable frequency and spreading factor, but can only demodulate a single data rate at a time. Finally channel 9 is a (G)FSK demodulator that is used to support the LR-FHSS channels, which use frequency hopping spread spectrum modulation instead of the LoRa chirp spread spectrum modulation used by the other channels.&lt;/p&gt;
&lt;p&gt;Given this, these are the important settings from the gateway configuration:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;region&lt;/code&gt;, &lt;code&gt;frequency_min&lt;/code&gt;, &lt;code&gt;frequency_max&lt;/code&gt;: These simply define what LoRa region that the gateway is operating in, which for me is the US915 band, which operates between 902Mhz and 928Mhz.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;backend.basic_station.concentrators.multi_sf&lt;/code&gt;: This specifies the channel frequencies for the first eight channels of the SX1308. Note that since the regional specification defies more 125Mhz channels than the SX1308 has, we have to pick a subset of the defined channels. I am simply using the first 8 128Khz LoRaWAN channels.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;backend.basic_station.concentrators.lora_std&lt;/code&gt;: The &lt;code&gt;frequency&lt;/code&gt;, &lt;code&gt;bandwidth&lt;/code&gt;, and &lt;code&gt;spreading_factor&lt;/code&gt; values in this group configure demodulation channel 8 in the SX1308. Since we already have 8 125Khz channels configured, I am using this channel for one of the 500khz channels, specifically LoRaWAN channel 64.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;gateway-packet-forwarder&#34;&gt;Gateway Packet Forwarder&lt;/h3&gt;
&lt;figure class=&#34;no-photoswipe&#34; style=&#34;--max-figure-height:200px;&#34;&gt;
  &lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 1
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 2
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 3
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 4
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 5
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 6
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 7
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 8
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 9
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;10
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;11
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;12
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;13
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;14
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;15
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;16
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;17
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;18
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;19
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;20
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;21
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;22
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;23
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;24
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;25
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;26
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;27
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;28
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;SX1301_conf&amp;#34;&lt;/span&gt;: {                  &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;/*&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;Actual&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;channel&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;plan&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;is&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;controlled&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;by&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;server&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;(ChirpStack&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;Gateway&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;Bridge)&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;*/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;device&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/dev/spidev0.0&amp;#34;&lt;/span&gt;,   &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;/*&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;Default&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;SPI&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;device&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;*/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;lorawan_public&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;,      &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;/*&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;Use&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;sync&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;header,&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;must&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;be&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;coordinated&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;with&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;all&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;devices&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;ahead&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;of&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;time&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;*/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;clksrc&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;,                  &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;/*&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;radio_1&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;provides&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;clock&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;to&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;concentrator&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;*/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;radio_0&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;type&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;SX1257&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;rssi_offset&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;-166.0&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;tx_enable&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;,        &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;/*&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;First&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;SX1257&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;device&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;is&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;used&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;transmitter&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;*/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;antenna_gain&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;radio_1&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;type&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;SX1257&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;rssi_offset&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;-166.0&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;tx_enable&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;        &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;/*&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;Second&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;SX&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1257&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;is&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;not&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;connected&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;to&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;transmit&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;path&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;*/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;pps&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;                  &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;/*&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;My&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;GPS&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;doesn&amp;#39;t&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;have&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;pps&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;output&lt;/span&gt;, &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;so&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;don&amp;#39;t&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;expect&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;it&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;*/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    },  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;station_conf&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;log_file&amp;#34;&lt;/span&gt;:  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;stderr&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;log_level&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;DEBUG&amp;#34;&lt;/span&gt;,  &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;/*&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;XDEBUG,DEBUG,VERBOSE,INFO,NOTICE,WARNING,ERROR,CRITICAL&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;*/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;log_size&amp;#34;&lt;/span&gt;:  &lt;span style=&#34;color:#ae81ff&#34;&gt;10000000&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;log_rotate&amp;#34;&lt;/span&gt;:  &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;,  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;CUPS_RESYNC_INTV&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;1s&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;gps&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/dev/serial0&amp;#34;&lt;/span&gt;,        &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;/*&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;GPS&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;Connected&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;to&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;serial0&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;device&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;*/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;pps&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;gps&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }   
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
  
    &lt;figcaption&gt;&lt;span&gt;station.conf&lt;/span&gt;&lt;/figcaption&gt;
  
&lt;/figure&gt;

&lt;p&gt;Finally the configuration for the Basic Station packet forwarder application just needs to be configured based on the hardware setup of our gateway. The important settings here are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;lorawan_public&lt;/code&gt;: Setting this option to &lt;code&gt;false&lt;/code&gt; which changes the LoRa sync header byte from the specification&amp;rsquo;s &lt;code&gt;0x34&lt;/code&gt; to &lt;code&gt;0x12&lt;/code&gt;. Since the sync header is used to identify the start of a packet, changing the sync header prevents packets on our private network from interfering with any public LoRaWAN network.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;clksrc&lt;/code&gt;: This indicates which of the two SX1257 radio front-ends generates the 32Mhz radio clock for the SX1308. On the Pygate module this is the second SX1257.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;radio0&lt;/code&gt;/&lt;code&gt;radio1&lt;/code&gt;: These groups configure the two SX1257 front-ends connected to the SX1308. The main difference between them is that on the Pygate module, the &amp;ldquo;radio0&amp;rdquo; transmit path is hooked up, and it is not for &amp;ldquo;radio1&amp;rdquo;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pps&lt;/code&gt;: Since my GPS module does not have a PPS output that I can connect to that SX1308 chip this gets set to false.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;setting-up-an-organization-and-application&#34;&gt;Setting Up an Organization and Application&lt;/h2&gt;
&lt;p&gt;Even once all these configurations are set up, I found I wasn&amp;rsquo;t done. We need to configure the ChirpStack application server to set up the logical network and applications. This is done through the application server&amp;rsquo;s web interface.&lt;/p&gt;
&lt;p&gt;Once logged into the ChirpStack application sever, we first need to setup the connection to the network server. In &amp;ldquo;Network-servers&amp;rdquo;, we add a new network server with a logical name for the network, and the host:port for network server. The host and port should be &amp;ldquo;chirpstack-network-server:8000&amp;rdquo;. This is also where we could set up TLS authentication and encryption between network and application servers.&lt;/p&gt;


&lt;div class=&#34;box &#34; &gt;
  &lt;figure  itemprop=&#34;associatedMedia&#34; itemscope itemtype=&#34;http://schema.org/ImageObject&#34;&gt;
    &lt;div class=&#34;img&#34;&gt;
      &lt;img itemprop=&#34;thumbnail&#34; src=&#34;https://prbs23.com/blog/blog/posts/getting-started-with-a-private-lorawan-network/chirpstack_connect_network_server.png&#34; alt=&#34;Adding network server connection to the application server.&#34;/&gt;
      &lt;a href=&#34;https://prbs23.com/blog/blog/posts/getting-started-with-a-private-lorawan-network/chirpstack_connect_network_server.png&#34; itemprop=&#34;contentUrl&#34;&gt;&lt;/a&gt;
    &lt;/div&gt;
      &lt;figcaption&gt;
          &lt;p&gt;
            Adding network server connection to the application server.
            
          &lt;/p&gt;
      &lt;/figcaption&gt;
  &lt;/figure&gt;
&lt;/div&gt;

&lt;p&gt;Next we must create an &amp;ldquo;organization&amp;rdquo; for our application network to run in. ChirpStack appears to be built from a network administrator perspective, and so provides &amp;ldquo;organizations&amp;rdquo; as a way to manage groups of users and applications. For a private LoRaWAN network this isn&amp;rsquo;t particularly useful, but we still need to set one up. Under &amp;ldquo;Organizations&amp;rdquo; we create a new organization a name, display name and permissions. For the permissions I selected &amp;ldquo;Organization can have gateways&amp;rdquo;.&lt;/p&gt;


&lt;div class=&#34;box &#34; &gt;
  &lt;figure  itemprop=&#34;associatedMedia&#34; itemscope itemtype=&#34;http://schema.org/ImageObject&#34;&gt;
    &lt;div class=&#34;img&#34;&gt;
      &lt;img itemprop=&#34;thumbnail&#34; src=&#34;https://prbs23.com/blog/blog/posts/getting-started-with-a-private-lorawan-network/chirpstack_create_organization.png&#34; alt=&#34;Creating an organization.&#34;/&gt;
      &lt;a href=&#34;https://prbs23.com/blog/blog/posts/getting-started-with-a-private-lorawan-network/chirpstack_create_organization.png&#34; itemprop=&#34;contentUrl&#34;&gt;&lt;/a&gt;
    &lt;/div&gt;
      &lt;figcaption&gt;
          &lt;p&gt;
            Creating an organization.
            
          &lt;/p&gt;
      &lt;/figcaption&gt;
  &lt;/figure&gt;
&lt;/div&gt;

&lt;p&gt;Now that we have an organization, we need to configure the service and device profiles. Each gateway and application is associated with a service profile that defines how the application/gateway can consume network resources. Each device is associated with a device profile which defines network and protocol parameters that are applied to a set of devices.&lt;/p&gt;
&lt;p&gt;First we create a new network service profile under &amp;ldquo;Service-profiles&amp;rdquo;. The profile has a name, an associated network server (we only have one option here), and other network settings. The ChirpStack defaults have the maximum allowed data rate set to DR0, which is the slowest LoRaWAN data rate. For our gateway configuration, the highest supported data rate is DR4, so setting the maximum allowed data-rate setting to 4 allows us to get the most per-device bandwidth out of the network.&lt;/p&gt;


&lt;div class=&#34;box &#34; &gt;
  &lt;figure  itemprop=&#34;associatedMedia&#34; itemscope itemtype=&#34;http://schema.org/ImageObject&#34;&gt;
    &lt;div class=&#34;img&#34;&gt;
      &lt;img itemprop=&#34;thumbnail&#34; src=&#34;https://prbs23.com/blog/blog/posts/getting-started-with-a-private-lorawan-network/chirpstack_create_service_profile.png&#34; alt=&#34;Creating a service profile.&#34;/&gt;
      &lt;a href=&#34;https://prbs23.com/blog/blog/posts/getting-started-with-a-private-lorawan-network/chirpstack_create_service_profile.png&#34; itemprop=&#34;contentUrl&#34;&gt;&lt;/a&gt;
    &lt;/div&gt;
      &lt;figcaption&gt;
          &lt;p&gt;
            Creating a service profile.
            
          &lt;/p&gt;
      &lt;/figcaption&gt;
  &lt;/figure&gt;
&lt;/div&gt;

&lt;p&gt;Next we create a device profile by under the &amp;ldquo;Device-profiles&amp;rdquo; sections. As with the service profile we need to give it a name and an associated network. Additionally we need to set the LoRaWAN protocol and regional parameters specification versions that will be used by the device. I&amp;rsquo;m using protocol spec version 1.0.4 because it is what was supported in the end-device firmware network stack, and regional parameters version RP002-1.0.3, since that is the latest version. Finally we need to configure the automatic data rate algorithm to &amp;ldquo;LoRa Only&amp;rdquo;, Since our gateway isn&amp;rsquo;t configured for LR-FHSS. On the &amp;ldquo;Join (OTAA/APB)&amp;rdquo; tab I also set &amp;ldquo;Device supports OTAA&amp;rdquo; to enable over the air activation protocol which allows the end-device and network server to negotiate network parameters without needing them to be configured out of band.&lt;/p&gt;
&lt;p&gt;To simplify logging data into my InfluxDB backend, I chose to enable the &amp;ldquo;Cayenne LPP&amp;rdquo; codec under the &amp;ldquo;Codec&amp;rdquo; tab of the device-profile settings. When enabled, the ChirpStack application server will assume uplink packets from devices with this profile are encoded with the &lt;a href=&#34;https://developers.mydevices.com/cayenne/docs/lora/#lora-cayenne-low-power-payload&#34;&gt;Cayenne LPP&lt;/a&gt; format, and automatically decoded them. This makes it simple encode basic binary values on the end-device and have them logged into the InfluxDB database in a meaningful way.&lt;/p&gt;


&lt;div class=&#34;box &#34; &gt;
  &lt;figure  itemprop=&#34;associatedMedia&#34; itemscope itemtype=&#34;http://schema.org/ImageObject&#34;&gt;
    &lt;div class=&#34;img&#34;&gt;
      &lt;img itemprop=&#34;thumbnail&#34; src=&#34;https://prbs23.com/blog/blog/posts/getting-started-with-a-private-lorawan-network/chirpstack_create_device_profile.png&#34; alt=&#34;Creating a device profile.&#34;/&gt;
      &lt;a href=&#34;https://prbs23.com/blog/blog/posts/getting-started-with-a-private-lorawan-network/chirpstack_create_device_profile.png&#34; itemprop=&#34;contentUrl&#34;&gt;&lt;/a&gt;
    &lt;/div&gt;
      &lt;figcaption&gt;
          &lt;p&gt;
            Creating a device profile.
            
          &lt;/p&gt;
      &lt;/figcaption&gt;
  &lt;/figure&gt;
&lt;/div&gt;

&lt;p&gt;With the profiles created we can now add a gateway to the organization. To do this, under &amp;ldquo;Gateways&amp;rdquo; we create a new gateway with a name and description, gateway ID, network server, and finally a service profile. The gateway ID is defined by the Basic Station packet forwarder application and by default is set to the MAC address of the primary network interface on the gateway. The network server and service profiles should be configured to the ones we have just created.&lt;/p&gt;


&lt;div class=&#34;box &#34; &gt;
  &lt;figure  itemprop=&#34;associatedMedia&#34; itemscope itemtype=&#34;http://schema.org/ImageObject&#34;&gt;
    &lt;div class=&#34;img&#34;&gt;
      &lt;img itemprop=&#34;thumbnail&#34; src=&#34;https://prbs23.com/blog/blog/posts/getting-started-with-a-private-lorawan-network/chirpstack_add_gateway.png&#34; alt=&#34;Add gateway to organization.&#34;/&gt;
      &lt;a href=&#34;https://prbs23.com/blog/blog/posts/getting-started-with-a-private-lorawan-network/chirpstack_add_gateway.png&#34; itemprop=&#34;contentUrl&#34;&gt;&lt;/a&gt;
    &lt;/div&gt;
      &lt;figcaption&gt;
          &lt;p&gt;
            Add gateway to organization.
            
          &lt;/p&gt;
      &lt;/figcaption&gt;
  &lt;/figure&gt;
&lt;/div&gt;

&lt;p&gt;Next we will finally set up the application that runs on top of our LoRaWAN network. To do this we just create a new application with a name and the service profile that we created previously.&lt;/p&gt;


&lt;div class=&#34;box &#34; &gt;
  &lt;figure  itemprop=&#34;associatedMedia&#34; itemscope itemtype=&#34;http://schema.org/ImageObject&#34;&gt;
    &lt;div class=&#34;img&#34;&gt;
      &lt;img itemprop=&#34;thumbnail&#34; src=&#34;https://prbs23.com/blog/blog/posts/getting-started-with-a-private-lorawan-network/chirpstack_add_application.png&#34; alt=&#34;Create application.&#34;/&gt;
      &lt;a href=&#34;https://prbs23.com/blog/blog/posts/getting-started-with-a-private-lorawan-network/chirpstack_add_application.png&#34; itemprop=&#34;contentUrl&#34;&gt;&lt;/a&gt;
    &lt;/div&gt;
      &lt;figcaption&gt;
          &lt;p&gt;
            Create application.
            
          &lt;/p&gt;
      &lt;/figcaption&gt;
  &lt;/figure&gt;
&lt;/div&gt;

&lt;p&gt;Once we have an application we need to tell ChirpStack what to do with packets once they are received, by choosing one or more &amp;ldquo;Integrations&amp;rdquo;. My goal for this initial setup was simply to log data into an InfluxDB time series database, conveniently ChirpStack has an integration with InfluxDB which stores data values from each uplink packet as decoded using the Cayenne LPP protocol. To enable this, under &amp;ldquo;Applications&amp;rdquo;-&amp;gt;&amp;ldquo;Integrations&amp;rdquo; we find the &amp;ldquo;InfluxDB&amp;rdquo; integration, add it to the application, then in the integration settings we will select InfluxDB 2.x for the protocol, &lt;code&gt;http://influxdb:8086/api/v2/write&lt;/code&gt; for the API InfluxDB endpoint (this is the docker internal hostname and port), and specify which bucket in the database it should put received packets into.&lt;/p&gt;


&lt;div class=&#34;box &#34; &gt;
  &lt;figure  itemprop=&#34;associatedMedia&#34; itemscope itemtype=&#34;http://schema.org/ImageObject&#34;&gt;
    &lt;div class=&#34;img&#34;&gt;
      &lt;img itemprop=&#34;thumbnail&#34; src=&#34;https://prbs23.com/blog/blog/posts/getting-started-with-a-private-lorawan-network/chirpstack_configure_influxdb_integration.png&#34; alt=&#34;Configuring influxdb integration.&#34;/&gt;
      &lt;a href=&#34;https://prbs23.com/blog/blog/posts/getting-started-with-a-private-lorawan-network/chirpstack_configure_influxdb_integration.png&#34; itemprop=&#34;contentUrl&#34;&gt;&lt;/a&gt;
    &lt;/div&gt;
      &lt;figcaption&gt;
          &lt;p&gt;
            Configuring influxdb integration.
            
          &lt;/p&gt;
      &lt;/figcaption&gt;
  &lt;/figure&gt;
&lt;/div&gt;

&lt;p&gt;Now we can finally add a our end-device to the application under the &amp;ldquo;Devices&amp;rdquo; tab, by selecting create and entering a device name, description, device EUI, and the previously created device profile. The Device EUI is a globally unique IEEE EUI64 identifier for the end-device, the CMWX1ZZABZ transceiver module comes pre-programmed with a Device EUI which will be used by firmware when sending join requests.&lt;/p&gt;


&lt;div class=&#34;box &#34; &gt;
  &lt;figure  itemprop=&#34;associatedMedia&#34; itemscope itemtype=&#34;http://schema.org/ImageObject&#34;&gt;
    &lt;div class=&#34;img&#34;&gt;
      &lt;img itemprop=&#34;thumbnail&#34; src=&#34;https://prbs23.com/blog/blog/posts/getting-started-with-a-private-lorawan-network/chirpstack_add_device.png&#34; alt=&#34;Addng end-device to application.&#34;/&gt;
      &lt;a href=&#34;https://prbs23.com/blog/blog/posts/getting-started-with-a-private-lorawan-network/chirpstack_add_device.png&#34; itemprop=&#34;contentUrl&#34;&gt;&lt;/a&gt;
    &lt;/div&gt;
      &lt;figcaption&gt;
          &lt;p&gt;
            Addng end-device to application.
            
          &lt;/p&gt;
      &lt;/figcaption&gt;
  &lt;/figure&gt;
&lt;/div&gt;

&lt;p&gt;Once the device has been created ChirpStack brings us to a page to enter or create an &amp;ldquo;Application Key&amp;rdquo;. This is a shared 128-bit key used by the end-device and network to derive encryption keys for all data sent across the network. It should be set to something random, and communicated to the end-device out of band.&lt;/p&gt;


&lt;div class=&#34;box &#34; &gt;
  &lt;figure  itemprop=&#34;associatedMedia&#34; itemscope itemtype=&#34;http://schema.org/ImageObject&#34;&gt;
    &lt;div class=&#34;img&#34;&gt;
      &lt;img itemprop=&#34;thumbnail&#34; src=&#34;https://prbs23.com/blog/blog/posts/getting-started-with-a-private-lorawan-network/chirpstack_set_device_key.png&#34; alt=&#34;Add end-device to application.&#34;/&gt;
      &lt;a href=&#34;https://prbs23.com/blog/blog/posts/getting-started-with-a-private-lorawan-network/chirpstack_set_device_key.png&#34; itemprop=&#34;contentUrl&#34;&gt;&lt;/a&gt;
    &lt;/div&gt;
      &lt;figcaption&gt;
          &lt;p&gt;
            Add end-device to application.
            
          &lt;/p&gt;
      &lt;/figcaption&gt;
  &lt;/figure&gt;
&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;And that&amp;rsquo;s it!&lt;/strong&gt; Our network and applications are set up and ready to go!&lt;/p&gt;
&lt;h2 id=&#34;sending-a-packet&#34;&gt;Sending a Packet&lt;/h2&gt;
&lt;p&gt;As previously mentioned, to test out the network I am running an example application which turns the CMWX1ZZABZ module into an AT style modem. I&amp;rsquo;m connecting to the modem firmware over the USB-Serial interface provided by the ST-Discovery development board I&amp;rsquo;m using.&lt;/p&gt;
&lt;p&gt;When the module comes out of reset we get the following output:
&lt;figure class=&#34;no-photoswipe&#34;&gt;
  &lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 1
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 2
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 3
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 4
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 5
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 6
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 7
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 8
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 9
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;10
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;11
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;12
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;13
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;14
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;APP_VERSION:        V1.1.0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;MW_LORAWAN_VERSION: V2.3.0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;MW_RADIO_VERSION:   V1.1.0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;###### OTAA ######
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;###### AppKey:      2B:7E:15:16:28:AE:D2:A6:AB:F7:15:88:09:CF:4F:3C
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;###### NwkKey:      2B:7E:15:16:28:AE:D2:A6:AB:F7:15:88:09:CF:4F:3C
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;###### ABP  ######
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;###### AppSKey:     2B:7E:15:16:28:AE:D2:A6:AB:F7:15:88:09:CF:4F:3C
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;###### NwkSKey:     2B:7E:15:16:28:AE:D2:A6:AB:F7:15:88:09:CF:4F:3C
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;###### DevEui:  XX:XX:XX:XX:XX:XX:XX:XX
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;###### AppEui:  01:01:01:01:01:01:01:01
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;###### DevAddr: XX:XX:XX:XX
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ATtention command interface
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;AT? to list all available functions
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
  
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;From here we can send the commands to have our end-device join the network. First we need to set the &lt;code&gt;NwkKey&lt;/code&gt; to the &amp;ldquo;Application Key&amp;rdquo; we configured in the ChirpStack UI previously, then send the join command:&lt;/p&gt;
&lt;figure class=&#34;no-photoswipe&#34;&gt;
  &lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;1
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;AT+NWKKEY=XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;AT+JOIN=1
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
  
&lt;/figure&gt;

&lt;p&gt;When everything works correctly I get an output like the following, indicating that we have joined the network.&lt;/p&gt;
&lt;figure class=&#34;no-photoswipe&#34;&gt;
  &lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 1
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 2
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 3
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 4
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 5
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 6
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 7
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 8
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 9
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;10
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;OK
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;299s464:TX on freq 903100000 Hz at DR 0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;OK
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;299s895:MAC txDone
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;304s884:RX_1 on freq 925700000 Hz at DR 10
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;305s018:MAC rxDone
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;+EVT:JOINED
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;+EVT:RX_1, DR 0, RSSI -80, SNR 8
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
  
&lt;/figure&gt;

&lt;p&gt;To send a packet we use the &lt;code&gt;AT+SEND&lt;/code&gt; command which takes three arguments: The LoRaWAN port, which can be anything other than 0 (port zero indicates network management packet), a 1 or 0 indicating if we want the network to confirm receipt of the packet, and finally the data to send as a hex string. Since I have configured ChirpStack to decode packets using the Cayenne LPP protocol, the message I&amp;rsquo;m sending is formatted using Cayenne LPP. The following command will send a packet with a value of 4.00 for the &amp;ldquo;Analog Input 3&amp;rdquo; value on port 100.&lt;/p&gt;
&lt;figure class=&#34;no-photoswipe&#34;&gt;
  &lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;AT+SEND=100:1:03020190
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
  
&lt;/figure&gt;

&lt;p&gt;In response the firmware gives us this output indicating that it sent our message and it was confirmed by the network:&lt;/p&gt;
&lt;figure class=&#34;no-photoswipe&#34;&gt;
  &lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;1
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;2
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;3
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;4
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;5
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;6
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;7
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;8
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;685s981:TX on freq 902500000 Hz at DR 0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;OK
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;686s333:MAC txDone
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;687s323:RX_1 on freq 923900000 Hz at DR 10
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;687s434:MAC rxDone
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;+EVT:SEND_CONFIRMED
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;+EVT:RX_1, DR 10, RSSI -75, SNR 8
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
  
&lt;/figure&gt;

&lt;p&gt;After sending a few of these messages, looking in the InfluxDB bucket I now have the data values from each packet I sent logged into the database, along with a little bit of metadata about it.&lt;/p&gt;


&lt;div class=&#34;box &#34; &gt;
  &lt;figure  itemprop=&#34;associatedMedia&#34; itemscope itemtype=&#34;http://schema.org/ImageObject&#34;&gt;
    &lt;div class=&#34;img&#34;&gt;
      &lt;img itemprop=&#34;thumbnail&#34; src=&#34;https://prbs23.com/blog/blog/posts/getting-started-with-a-private-lorawan-network/influxdb_example_data.png&#34; alt=&#34;Data from packets logged into InfluxDB database.&#34;/&gt;
      &lt;a href=&#34;https://prbs23.com/blog/blog/posts/getting-started-with-a-private-lorawan-network/influxdb_example_data.png&#34; itemprop=&#34;contentUrl&#34;&gt;&lt;/a&gt;
    &lt;/div&gt;
      &lt;figcaption&gt;
          &lt;p&gt;
            Data from packets logged into InfluxDB database.
            
          &lt;/p&gt;
      &lt;/figcaption&gt;
  &lt;/figure&gt;
&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Success!&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&#34;next-steps&#34;&gt;Next Steps&lt;/h2&gt;
&lt;p&gt;Now that I have a working LoRaWAN network, there are several areas that I will be investigating in the future.&lt;/p&gt;
&lt;p&gt;To start with I have just been using the built in InfluxDB integration and Cayenne LPP packet format built into ChirpStack to log basic data. Of course the LoRaWAN network supports sending any data with any protocol, so now that I can reliably send data there are a lot of options of both custom and built in protocols that can be layered on top of LoRaWAN and ChirpStack.&lt;/p&gt;
&lt;p&gt;Additionally, I have just been using the CMWX1ZZABZ as a dumb modem to manually transmit packets/data over the network. For a real application of my LoRaWAN network I need to develop firmware for the CMWX1ZZABZ to actual interface with sensors and send the data to the network.&lt;/p&gt;
&lt;p&gt;Finally, as previously mentioned I have not configured all the authentication and authorization features in the ChirpStack architecture. I need to spend some more time investigating and learning how to configure these to better secure my network.&lt;/p&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;Technically in some regions such as US915 it is valid to only support a single channel, in which case a single transceiver could act as a gateway. A proof of concept implementation for this can be found in this &amp;ldquo;&lt;a href=&#34;https://github.com/sealj553/lorawan-gateway&#34;&gt;Single Channel LoRaWAN Gateway&lt;/a&gt;&amp;rdquo; project on Github. However in other regions such as EU868 region, for example, a &lt;a href=&#34;https://content.cdntwrk.com/files/aT0xNDI4MzI2JnY9MSZpc3N1ZU5hbWU9cnAyLTEtMC0zLWxvcmF3YW4tcmVnaW9uYWwtcGFyYW1ldGVycyZjbWQ9ZCZzaWc9ZDI4NDMxYzU2NTVjZjZjZDRiYzJiM2ExZGEwMTAzMmM%253D#page=25&#34;&gt;gateway is &lt;em&gt;required&lt;/em&gt; to support&lt;/a&gt; at a minimum of three specific channels.&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:2&#34;&gt;
&lt;p&gt;Theoretically ChirpStack also includes its own equivalent to the Basics Station application, in the form of &lt;a href=&#34;https://www.chirpstack.io/concentratord/&#34;&gt;Concentratord&lt;/a&gt;. However on the integration between the Concentratord and the Gateway Bridge is &lt;a href=&#34;https://www.chirpstack.io/gateway-bridge/backends/concentratord/&#34;&gt;currently listed as &amp;ldquo;experimental&amp;rdquo;&lt;/a&gt;, so I have not actually tried this out.&amp;#160;&lt;a href=&#34;#fnref:2&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
</description>
    </item>
    
    <item>
      <title>Don&#39;t Wait For Me</title>
      <link>https://prbs23.com/blog/posts/systemverilog-wait-fork/</link>
      <pubDate>Thu, 17 Feb 2022 22:22:26 -0700</pubDate>
      <author>prbs23@prbs23.com (prbs23)</author>
      <guid>https://prbs23.com/blog/posts/systemverilog-wait-fork/</guid>
      <description>&lt;p&gt;From the perspective your more traditional software programming languages, multi-tasking in SystemVerilog is weird. On one hand, the language includes a special syntax (&lt;code&gt;fork&lt;/code&gt; and &lt;code&gt;join&lt;/code&gt;) that make it really easy to write code that &amp;ldquo;runs&amp;rdquo; in parallel. On the other hand, SystemVerilog &amp;ldquo;processes&amp;rdquo; aren&amp;rsquo;t really processes, or even threads, in the traditional sense. Even if you &amp;ldquo;get&amp;rdquo; the SystemVerilog model of cooperative &lt;a href=&#34;https://en.wikipedia.org/wiki/Cooperative_multitasking&#34;&gt;cooperative multi-tasking&lt;/a&gt;, there are a number of pitfalls you can run into. One such gotcha that I recently ran into was caused by what appeared to be an innocuous &lt;code&gt;wait fork&lt;/code&gt; statement.&lt;/p&gt;
&lt;h2 id=&#34;an-unexpected-infinite-wait&#34;&gt;An Unexpected Infinite Wait&lt;/h2&gt;
&lt;figure class=&#34;no-photoswipe&#34;&gt;
  &lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 1
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 2
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 3
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 4
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 5
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 6
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 7
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 8
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 9
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;10
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;11
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;12
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;13
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-systemverilog&#34; data-lang=&#34;systemverilog&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;initial&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;begin&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;bit&lt;/span&gt; [&lt;span style=&#34;color:#ae81ff&#34;&gt;31&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;] data;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;fork&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;forever&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;begin&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#75715e&#34;&gt;// Monitor some signals for correct behavior.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;join_none&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;// Do some other stuff. Then...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;  do_read(&lt;span style=&#34;color:#ae81ff&#34;&gt;32&amp;#39;hdead&lt;/span&gt;_beef, &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;, data);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  $display(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Done&amp;#34;&lt;/span&gt;); &lt;span style=&#34;color:#75715e&#34;&gt;// &amp;lt;--- This print never happens
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
  
    &lt;figcaption&gt;&lt;span&gt;The initial problem code structure&lt;/span&gt;&lt;/figcaption&gt;
  
&lt;/figure&gt;

&lt;p&gt;The issue was in an old (I mean &lt;em&gt;really&lt;/em&gt; old, pre-UVM) test case that hadn&amp;rsquo;t been run in a long time, and appeared to hang in a task that issued an bus read transaction. From inspecting the simulation waves and logs, I could tell that the bus transaction was completing without issue, but the task was still never returning. The basic structure of this the test code is shown above, a process is forked off, then the &lt;code&gt;do_read()&lt;/code&gt; task is called. This obviously calls the content of &lt;code&gt;do_read()&lt;/code&gt; into question, after digging through a few translation layers (did I mention this code was old), I found the code that actually did the bus transaction, which I&amp;rsquo;ll call &lt;code&gt;do_read_internal()&lt;/code&gt;, looked something like this:&lt;/p&gt;
&lt;figure class=&#34;no-photoswipe&#34;&gt;
  &lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 1
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 2
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 3
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 4
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 5
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 6
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 7
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 8
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 9
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;10
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;11
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;12
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;13
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;14
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;15
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;16
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-systemverilog&#34; data-lang=&#34;systemverilog&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;task&lt;/span&gt; do_read_internal(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;input&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;bit&lt;/span&gt; [&lt;span style=&#34;color:#ae81ff&#34;&gt;31&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;] addr,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;input&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; byte_size,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;output&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;bit&lt;/span&gt; [&lt;span style=&#34;color:#ae81ff&#34;&gt;31&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;] data,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;input&lt;/span&gt; flags_t flags &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; NONE
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;fork&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;begin&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#75715e&#34;&gt;// Wiggle bus wires and pass time as required do drive transaction
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;join_none&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (flags &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt; BLOCKING_TRANSACTION) &lt;span style=&#34;color:#66d9ef&#34;&gt;begin&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;wait&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;fork&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;endtask&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; do_read_internal
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
  
    &lt;figcaption&gt;&lt;span&gt;do_read_internal() task called by test case through do_read() task&lt;/span&gt;&lt;/figcaption&gt;
  
&lt;/figure&gt;

&lt;p&gt;Now, if you know what you&amp;rsquo;re looking for you may already see the issue. But before I give it all away, suffice it to say, the problem here is the use of the &lt;code&gt;wait fork&lt;/code&gt; statement. So let&amp;rsquo;s talk about what that last &lt;code&gt;wait fork&lt;/code&gt; statement is actually doing.&lt;/p&gt;
&lt;h2 id=&#34;a-not-so-brief-introduction-to-wait-fork&#34;&gt;A Not So Brief Introduction to &lt;code&gt;wait fork&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Lets start in the obvious place, what does the SystsemVerilog LRM (Language Reference Manual) say about &lt;code&gt;wait fork&lt;/code&gt;? This is summary of the statement that we can find in section &lt;strong&gt;9.6.1 Wait fork statement&lt;/strong&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The &lt;code&gt;wait fork&lt;/code&gt; statement blocks process execution flow until all immediate child subprocesses (processes created by the current process, excluding their descendants) have completed their execution.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This seems fairly simple, it is a statement that makes a process wait until all sub-processes that were started from the current process have finished. The problem with this construct is that it&amp;rsquo;s not always obvious which processes &amp;ldquo;all immediate child subprocesses&amp;rdquo; refer to. Lets start with a simple example:&lt;/p&gt;
&lt;figure class=&#34;no-photoswipe&#34;&gt;
  &lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 1
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 2
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 3
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 4
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 5
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 6
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 7
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 8
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 9
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;10
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;11
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;12
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;13
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-systemverilog&#34; data-lang=&#34;systemverilog&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;initial&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;begin&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; main_process
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;fork&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;begin&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; subprocess_1;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      #&lt;span style=&#34;color:#ae81ff&#34;&gt;100&lt;/span&gt; $display(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;%t: Hello from subprocess_1&amp;#34;&lt;/span&gt;, $time());
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;end&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; subprocess_1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;begin&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; subprocess_2;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      #&lt;span style=&#34;color:#ae81ff&#34;&gt;50&lt;/span&gt; $display(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;%t: Hello from subprocess_2&amp;#34;&lt;/span&gt;, $time());
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;end&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; subprocess_2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;join_none&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;wait&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;fork&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  $display(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;%t: Done&amp;#34;&lt;/span&gt;, $time());
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;end&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; main_process
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
  
    &lt;figcaption&gt;&lt;span&gt;Trivial wait fork example&lt;/span&gt;&lt;/figcaption&gt;
  
&lt;/figure&gt;

&lt;p&gt;In this case the &lt;code&gt;fork&lt;/code&gt;/&lt;code&gt;join_none&lt;/code&gt; block is going to spawn two subprocesses which wait for a period of time and then print a message. Because a &lt;code&gt;join_none&lt;/code&gt; was used, execution of the &lt;code&gt;main_process&lt;/code&gt; block will not wait for these subprocesses to finish before continuing. Then the &lt;code&gt;wait fork&lt;/code&gt; statement will wait for both the two subprocesses running the &lt;code&gt;subprocess_1&lt;/code&gt; and &lt;code&gt;subprocess_2&lt;/code&gt; blocks to finish, and then print &amp;ldquo;Done&amp;rdquo;. Easy enough. Now, what if we make it a bit more complicated and move the &lt;code&gt;wait fork&lt;/code&gt; into another task.&lt;/p&gt;
&lt;figure class=&#34;no-photoswipe&#34;&gt;
  &lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 1
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 2
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 3
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 4
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 5
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 6
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 7
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 8
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 9
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;10
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;11
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;12
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;13
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;14
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;15
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;16
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;17
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;18
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;19
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;20
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;21
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;22
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;23
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;24
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;25
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;26
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-systemverilog&#34; data-lang=&#34;systemverilog&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;initial&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;begin&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; main_process
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;fork&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;begin&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; subprocess_1;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      #&lt;span style=&#34;color:#ae81ff&#34;&gt;100&lt;/span&gt; $display(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;%t: Hello from subprocess_1&amp;#34;&lt;/span&gt;, $time());
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;end&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; subprocess_1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;begin&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; subprocess_2;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      #&lt;span style=&#34;color:#ae81ff&#34;&gt;50&lt;/span&gt; $display(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;%t: Hello from subprocess_2&amp;#34;&lt;/span&gt;, $time());
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;end&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; subprocess_2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;join_none&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  task_1();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  $display(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;%t: Done&amp;#34;&lt;/span&gt;, $time());
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;end&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; main_process
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;task&lt;/span&gt; task_1();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;fork&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;begin&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; subprocess_3;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      #&lt;span style=&#34;color:#ae81ff&#34;&gt;25&lt;/span&gt; $display(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;%t: Hello from subprocess_3&amp;#34;&lt;/span&gt;, $time());
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;end&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; subprocess_3
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;begin&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; subprocess_4;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      #&lt;span style=&#34;color:#ae81ff&#34;&gt;75&lt;/span&gt; $display(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;%t: Hello from subprocess_4&amp;#34;&lt;/span&gt;, $time());
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;end&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; subprocess_4
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;join_none&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;wait&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;fork&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;endtask&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; task_1
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
  
    &lt;figcaption&gt;&lt;span&gt;What happens when we move the wait fork into a task?&lt;/span&gt;&lt;/figcaption&gt;
  
&lt;/figure&gt;

&lt;p&gt;In this case we start subprocesses &lt;code&gt;subprocess_1&lt;/code&gt; and &lt;code&gt;subprocess_2&lt;/code&gt;, and don&amp;rsquo;t wait for them to finish, just like the previous example. However we now call a task &lt;code&gt;task_1()&lt;/code&gt; which also spawns two new processes &lt;code&gt;subprocess_3&lt;/code&gt; and &lt;code&gt;subprocess_4&lt;/code&gt;, then executes a &lt;code&gt;wait fork&lt;/code&gt; statement, before returning and printing &amp;ldquo;Done&amp;rdquo;. If &lt;code&gt;wait fork&lt;/code&gt; followed normal scoping rules like one might naively expect it to wait for subprocesses 3 and 4 only, but if we look at the output from this example, we see this is not the case.&lt;/p&gt;
&lt;figure class=&#34;no-photoswipe&#34;&gt;
  &lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;1
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;2
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;3
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;4
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;5
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;6
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;xcelium&amp;gt; run
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  25: Hello from subprocess_3
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  50: Hello from subprocess_2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  75: Hello from subprocess_4
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 100: Hello from subprocess_1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 100: Done
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
  
&lt;/figure&gt;

&lt;p&gt;The reason that the &lt;code&gt;wait fork&lt;/code&gt; waits for all four of the spawned subprocess to finish, is that simply that they are all subprocesses of the process from which &lt;code&gt;wait fork&lt;/code&gt; was called, the one started from the &lt;code&gt;main_process&lt;/code&gt; initial block. This is because calling a task or another SystemVerilog scope doesn&amp;rsquo;t start a new process, in fact the only way that a new process is spawned (from an existing one) is through a fork statement. Because the code running in &lt;code&gt;task_1&lt;/code&gt; is still part of the same process, &amp;ldquo;all immediate subprocesses&amp;rdquo; includes &lt;code&gt;subprocess_1&lt;/code&gt; and &lt;code&gt;subprocess_2&lt;/code&gt;.&lt;/p&gt;
&lt;figure class=&#34;no-photoswipe&#34;&gt;
  &lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 1
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 2
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 3
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 4
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 5
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 6
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 7
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 8
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 9
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;10
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;11
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;12
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;13
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;14
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;15
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;16
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;17
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;18
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;19
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;20
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;21
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;22
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;23
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;24
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;25
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;26
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;27
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;28
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;29
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;30
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;31
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;32
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;33
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-systemverilog&#34; data-lang=&#34;systemverilog&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;initial&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;begin&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; main_process
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  task_1();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  task_2();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  $display(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;%t: Done&amp;#34;&lt;/span&gt;, $time());
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;end&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; main_process
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;task&lt;/span&gt; task_1();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;fork&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;begin&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; infinite_subprocess
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#66d9ef&#34;&gt;forever&lt;/span&gt; #&lt;span style=&#34;color:#ae81ff&#34;&gt;100&lt;/span&gt; $display(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;%t Hello again from infinite_subprocess&amp;#34;&lt;/span&gt;, $time());
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;end&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; infinite_subprocess
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;begin&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; subprocess_1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#66d9ef&#34;&gt;fork&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;begin&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; infinite_sub_subprocess
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#66d9ef&#34;&gt;forever&lt;/span&gt; #&lt;span style=&#34;color:#ae81ff&#34;&gt;75&lt;/span&gt; $display(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;%t Hello again from infinite_sub_subprocess&amp;#34;&lt;/span&gt;, $time());
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;end&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; infinite_sub_subprocess
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#66d9ef&#34;&gt;join_none&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;end&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; subprocess_1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;join_none&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;endtask&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; task_1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;task&lt;/span&gt; task_2();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;fork&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;begin&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; subprocess_2;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      #&lt;span style=&#34;color:#ae81ff&#34;&gt;25&lt;/span&gt; $display(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;%t: Hello from subprocess_2&amp;#34;&lt;/span&gt;, $time());
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;end&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; subprocess_2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;begin&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; subprocess_3;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      #&lt;span style=&#34;color:#ae81ff&#34;&gt;75&lt;/span&gt; $display(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;%t: Hello from subprocess_3&amp;#34;&lt;/span&gt;, $time());
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;end&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; subprocess_3
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;join_none&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;wait&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;fork&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;endtask&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; task_2
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
  
    &lt;figcaption&gt;&lt;span&gt;A wait fork example that will hang forever&lt;/span&gt;&lt;/figcaption&gt;
  
&lt;/figure&gt;

&lt;p&gt;This final example demonstrates, in a more obvious way, the bug in my problem code above. In this case, the task &lt;code&gt;task_1&lt;/code&gt; is first called from &lt;code&gt;main_process&lt;/code&gt; which starts two subprocesses &lt;code&gt;infinite_subprocess&lt;/code&gt; and &lt;code&gt;subprocess_1&lt;/code&gt;, then immediately returns because the block is terminated with &lt;code&gt;join_none&lt;/code&gt;. Then &lt;code&gt;task_2&lt;/code&gt; is executed, which forks two more processes (&lt;code&gt;subprocess_2&lt;/code&gt; and &lt;code&gt;subprocess_3&lt;/code&gt;) and finally executes a &lt;code&gt;wait fork&lt;/code&gt; statement. In this case the &lt;code&gt;wait fork&lt;/code&gt; statement is &lt;em&gt;never&lt;/em&gt; actually going to finish, because it has to wait for the conspicuously named &lt;code&gt;infinite_subprocess&lt;/code&gt; (which never ends), even though it was started from a different task.&lt;/p&gt;
&lt;p&gt;Finally, note that the &lt;code&gt;wait fork&lt;/code&gt; in &lt;code&gt;task_2&lt;/code&gt; does &lt;em&gt;not&lt;/em&gt; have to wait for the process &lt;code&gt;infinite_sub_subprocess&lt;/code&gt; because it is not a &lt;em&gt;direct&lt;/em&gt; subprocess of the &lt;code&gt;main_process&lt;/code&gt;. The &lt;code&gt;infinite_sub_subprocess&lt;/code&gt; process is forked from the &lt;code&gt;subprocess_1&lt;/code&gt; process, but because it uses &lt;code&gt;join_none&lt;/code&gt;, the process does not wait for &lt;code&gt;infinite_sub_subprocess&lt;/code&gt;, and leaves the sub-subprocess running, unattached, from any parent process.&lt;/p&gt;
&lt;h2 id=&#34;what-went-wrong&#34;&gt;What Went Wrong?&lt;/h2&gt;
&lt;p&gt;Going back to my hanging test case. Now that we&amp;rsquo;ve looked at some examples of how &lt;code&gt;wait fork&lt;/code&gt; works, it&amp;rsquo;s pretty obvious if you know where to look. The main test code starts an infinite process, and then calls a task which start it&amp;rsquo;s own process and then uses &lt;code&gt;wait fork&lt;/code&gt; to wait for it&amp;rsquo;s process, but unintentionally ends up waiting on an infinite loop to end. The &lt;code&gt;do_read_internal&lt;/code&gt; task has no visibility to know that an infinite process has even been spawned from it&amp;rsquo;s process, but &lt;code&gt;wait fork&lt;/code&gt; will wait for it anyway.&lt;/p&gt;
&lt;p&gt;The thing I find devious about this bug is that it demonstrates how starting of a subprocess in one place can cause a completely unrelated piece of code to hang, potentially forever. In fact it is entirely possible that the code that starts the infinite loop subprocess is in one library and the &lt;code&gt;wait fork&lt;/code&gt; statement is in another library. All that is required to cause havoc is that they are called from the same process. When I realized this it made me reconsider the safety of using &lt;code&gt;wait fork&lt;/code&gt;, and at this point it seems like it&amp;rsquo;s only really safe to use in very specific applications.&lt;/p&gt;
&lt;h2 id=&#34;remediation&#34;&gt;Remediation&lt;/h2&gt;
&lt;p&gt;Unfortunately, there is not a version of &lt;code&gt;wait fork&lt;/code&gt; with a more limited scope (such as waiting for subprocess of the current task or scope). This leaves us with three, not great, alternatives to implement the functionality that our &lt;code&gt;do_read_internal&lt;/code&gt; was going for: starting a non-block process, and then conditionally waiting for it to finish.&lt;/p&gt;
&lt;p&gt;The first, and in my opinion best, option in this case is to simply declare an event that gets emitted by the started subprocess on completion. Then to wait for the subprocess to end, the main process can just wait on the event, instead of using &lt;code&gt;wait fork&lt;/code&gt;. Aside from needing to declare a new event variable, this works fairly well if there is only one subprocess to wait on. This implementation would look something like the following:&lt;/p&gt;
&lt;figure class=&#34;no-photoswipe&#34;&gt;
  &lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 1
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 2
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 3
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 4
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 5
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 6
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 7
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 8
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 9
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;10
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-systemverilog&#34; data-lang=&#34;systemverilog&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;event&lt;/span&gt; done_event;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;fork&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;begin&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// Wiggle bus wires and pass time as required do drive transaction
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; done_event;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;join_none&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (flags &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt; BLOCKING_TRANSACTION) &lt;span style=&#34;color:#66d9ef&#34;&gt;begin&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  @done_event; &lt;span style=&#34;color:#75715e&#34;&gt;// Wait or forked subprocess to report it has ended.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
  
    &lt;figcaption&gt;&lt;span&gt;do_read_internal() task which uses a done event for waiting.&lt;/span&gt;&lt;/figcaption&gt;
  
&lt;/figure&gt;

&lt;p&gt;Another option is to use the SystemVerilog &amp;ldquo;fine-grain process control&amp;rdquo; features (see section 9.7 of the LRM). Essentially this feature provides an API to get a reference to a &amp;ldquo;process&amp;rdquo; object associated with the current process, which can then be used to wait on or otherwise manage the process. In this case, we can have the subprocess store it&amp;rsquo;s &amp;ldquo;process&amp;rdquo; object in a variable, and then use the &lt;code&gt;await()&lt;/code&gt; task of the process object to wait for the subprocess to end. Something like the following:&lt;/p&gt;
&lt;figure class=&#34;no-photoswipe&#34;&gt;
  &lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 1
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 2
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 3
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 4
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 5
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 6
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 7
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 8
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 9
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;10
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;11
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-systemverilog&#34; data-lang=&#34;systemverilog&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;process subprocess_handle;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;fork&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;begin&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    subprocess_handle &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; process&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;self(); &lt;span style=&#34;color:#75715e&#34;&gt;// Get process handle object for subprocess.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// Wiggle bus wires and pass time as required do drive transaction
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;join_none&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (flags &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt; BLOCKING_TRANSACTION) &lt;span style=&#34;color:#66d9ef&#34;&gt;begin&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  #&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;;                        &lt;span style=&#34;color:#75715e&#34;&gt;// Ensure that the subprocess has a chance to execute, so that the subprocess_handle will not be null.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;  subprocess_handle.await(); &lt;span style=&#34;color:#75715e&#34;&gt;// Wait for the subprocess to finish
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
  
    &lt;figcaption&gt;&lt;span&gt;do_read_internal() task using fine-grain process control to wait for subprocess&lt;/span&gt;&lt;/figcaption&gt;
  
&lt;/figure&gt;

&lt;p&gt;The two options above work fine when you are starting a single subprocess, and then want to conditionally wait for it to finish, but what if you are starting an indeterminate number of processes and want to wait for them to all finish? In this case the behavior of &lt;code&gt;wait fork&lt;/code&gt; to wait for all subprocesses is a really convenient feature. However as we have seen, when calling &lt;code&gt;wait fork&lt;/code&gt; you need to ensure you know which subprocesses it will actually wait for. The only way to really do this for sure, is to fork a new process within which we carefully control which processes are started. This does have the overhead of creating an extra another process, but this could be reasonable trade-off in some cases. An example of this implementation is shown below.&lt;/p&gt;
&lt;figure class=&#34;no-photoswipe&#34;&gt;
  &lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 1
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 2
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 3
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 4
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 5
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 6
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 7
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 8
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 9
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;10
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;11
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-systemverilog&#34; data-lang=&#34;systemverilog&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;fork&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;begin&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;// Start a new process for the content of the task
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;fork&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;begin&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#75715e&#34;&gt;// Wiggle bus wires and pass time as required do drive transaction
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;join_none&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (flags &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt; BLOCKING_TRANSACTION) &lt;span style=&#34;color:#66d9ef&#34;&gt;begin&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;wait&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;fork&lt;/span&gt;; &lt;span style=&#34;color:#75715e&#34;&gt;// This call is now safe, because we are gaurenteed there is only one subprocess.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;end&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;join&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;// Block until this wrapper process finishes.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
  
    &lt;figcaption&gt;&lt;span&gt;do_read_internal() task using an extra subprocess to control the scope of wait fork&lt;/span&gt;&lt;/figcaption&gt;
  
&lt;/figure&gt;

&lt;h2 id=&#34;conclusions&#34;&gt;Conclusions&lt;/h2&gt;
&lt;p&gt;In the end, I chose to take the first option and replace the &lt;code&gt;wait fork&lt;/code&gt; with a wait on a &lt;code&gt;done&lt;/code&gt; event, and everything works fine. However, I am also now taking a much more critical look at all other uses of &lt;code&gt;wait fork&lt;/code&gt; in our repository, as I now have a better appreciation for some of the pitfalls of this statement.&lt;/p&gt;
&lt;p&gt;There are certainly places where it is mostly safe. Use of &lt;code&gt;wait fork&lt;/code&gt; directly within a fork/join block is generally safe because it&amp;rsquo;s harder to get an unexpected subprocess. Likewise use within a UVM sequence &lt;code&gt;body()&lt;/code&gt; task also appears to be fairly safe, because sequence bodies are always started in a new process. However, even in these fairly well controlled uses it is important to remember that any task or function that is called &lt;em&gt;could&lt;/em&gt; start an unexpected infinite subprocess, and then we&amp;rsquo;re right back to the same problem.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m not saying don&amp;rsquo;t use &lt;code&gt;wait fork&lt;/code&gt;, but I do think it needs to be used with caution. It is easy to forget, or not be aware of, what all it will wait for.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Considering SystemVerilog Tagged Unions</title>
      <link>https://prbs23.com/blog/posts/considering-systemverilog-tagged-unions/</link>
      <pubDate>Sat, 22 Jan 2022 11:42:00 -0700</pubDate>
      <author>prbs23@prbs23.com (prbs23)</author>
      <guid>https://prbs23.com/blog/posts/considering-systemverilog-tagged-unions/</guid>
      <description>&lt;p&gt;I have recently been thinking a lot about tagged unions in SystemVerilog, since I discovered them a few months ago. In this post I present some of the ideal use cases for tagged unions, and why I think no one actually uses them.&lt;/p&gt;
&lt;p&gt;Despite being &lt;a href=&#34;https://accellera.org/images/eda/sv-bc/att-1352/01-2003-12-09_TaggedUnions_Proposal.pdf&#34;&gt;initially proposed in 2003&lt;/a&gt;, and officially part of the language since the &lt;a href=&#34;https://ieeexplore.ieee.org/document/1560791&#34;&gt;SystemVerilog 1800-2005 standard&lt;/a&gt; was released, at this point tagged unions appear to be a forgotten language feature. I think this is a shame, because since I accidentally ran across the tagged union section of the LRM, I keep thinking of new applications where I would like to make use of them. Don&amp;rsquo;t get me wrong, there are plenty of reasons that you don&amp;rsquo;t see tagged unions used in the wild today (language ergonomics, tool support, etc.) but that doesn&amp;rsquo;t mean they couldn&amp;rsquo;t have been useful.&lt;/p&gt;
&lt;h2 id=&#34;quick-introduction-to-sum-types&#34;&gt;Quick Introduction to Sum Types&lt;/h2&gt;
&lt;p&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/Tagged_union&#34;&gt;Tagged unions&lt;/a&gt;, commonly also referred to as &amp;ldquo;sum types&amp;rdquo;, at least in SystemVerilog, I like to think of a combination of two more commonly used data types, unions, and enums. Like an enum, the primary value (tag) of a tagged union variable can be one of several values, as defined by the type declaration. However, unlike a normal enum, along with the &amp;ldquo;tag&amp;rdquo;, the tagged union variable can store another value of a type defined by the tag. Each tag value can define a different type of value held by the union when the variable has that tag value. The syntax of tagged unions allow the compiler to enforce that the type of value assigned to the tagged union matches the type as defined by the tag, and it is always possible to know the type of value stored in the variable by looking at the tag, unlike a regular union.&lt;/p&gt;
&lt;p&gt;By way of example, in the following code, we declare a tagged union type &lt;code&gt;int_or_float_t&lt;/code&gt;, when assigned the tag &lt;code&gt;INT_VAL&lt;/code&gt; it is guaranteed by the compiler to hold an integer value, and when assigned the tag &lt;code&gt;FLOAT_VAL&lt;/code&gt; always a float value.&lt;/p&gt;
&lt;figure class=&#34;no-photoswipe&#34;&gt;
  &lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;1
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;2
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;3
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;4
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-systemverilog&#34; data-lang=&#34;systemverilog&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;typedef&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;union&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;tagged&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;   INT_VAL;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  float FLOAT_VAL
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;} int_or_float_t;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
  
    &lt;figcaption&gt;&lt;span&gt;Simple tagged union example.&lt;/span&gt;&lt;/figcaption&gt;
  
&lt;/figure&gt;

&lt;p&gt;Unlike a normal union, if you assign a &lt;code&gt;int_or_float_t&lt;/code&gt; variable to &lt;code&gt;INT_VAL&lt;/code&gt; with an associate integer value, the language will not allow us to refer to the integer value as a float. It will either be a compile time or runtime error, depending on the syntax used.&lt;/p&gt;
&lt;h2 id=&#34;why-not-to-use-tagged-unions&#34;&gt;Why not to use tagged unions&lt;/h2&gt;
&lt;p&gt;Before getting into why I think tagged unions should be used more, why have they been essentially forgotten in SystemVerilog? I believe this mainly comes down to two issues: lack of support from major simulator vendors and language ergonomics.&lt;/p&gt;
&lt;h3 id=&#34;lacking-support&#34;&gt;Lacking Support&lt;/h3&gt;
&lt;p&gt;Of the three major commercial simulators I recently tested, one (Cadence Xcelium) didn&amp;rsquo;t support tagged unions at all, and the other two (Mentor Questa and Synopsys VCS) have varying degrees of partial support. In my opinion this is the biggest reason we don&amp;rsquo;t see tagged unions used, if a feature isn&amp;rsquo;t supported by all of the big three simulators then it can&amp;rsquo;t be used in any portable VIP or standard libraries. Even in the two simulators that did have support, sadly neither supported constraining or randomizing tagged union variables. Being able to randomize both the tag and values of a tagged union would provide some interesting capabilities as I will discuss later.&lt;/p&gt;
&lt;h3 id=&#34;ergonomics&#34;&gt;Ergonomics&lt;/h3&gt;
&lt;p&gt;The other problem with tagged unions is that the syntax for using them is in some ways&amp;hellip; clunky at best. The pattern matching &lt;code&gt;case&lt;/code&gt; and &lt;code&gt;if&lt;/code&gt; syntax, which is (pretty much) required to check the tag and access values of the tagged union are both fairly verbose with lots of additional &lt;code&gt;tagged&lt;/code&gt;, &lt;code&gt;matches&lt;/code&gt; kind of keywords. Even assignments to the union value (tag) require an additional &lt;code&gt;tagged&lt;/code&gt; keyword. Additionally, unlike other language which have an equivalent tagged union or sum type, SystemVerilog doesn&amp;rsquo;t provide a way to &amp;ldquo;parameterize&amp;rdquo; or &amp;ldquo;template&amp;rdquo; the types held by a tagged union.&lt;/p&gt;
&lt;p&gt;Between lack of support, and generally feeling like a feature that was added to the language without a huge amount of thought, I can&amp;rsquo;t really blame anyone for not using tagged unions. However I am, none the less, disappointed that I can&amp;rsquo;t use them because they are not supported by the tools I use every day. After having used sum types in other languages, I think they could bring a lot of value to verification code written in SystemVerilog.&lt;/p&gt;
&lt;h2 id=&#34;uses-of-tagged-unions&#34;&gt;Uses of Tagged Unions&lt;/h2&gt;
&lt;p&gt;Now if we ignore the legitimate issues with tagged unions discussed above, what could they be used for? Note that the proposals below are pretty much all currently theoretical. I haven&amp;rsquo;t tried to implement these, and some are even impossible today due to missing support in current tools (especially around randomization and constraints). Nevertheless, I think these ideas are worth more investigation, and would love to hear from anyone who has done anything similar in SV.&lt;/p&gt;
&lt;h3 id=&#34;error-handling-using-result-types&#34;&gt;Error Handling using &amp;ldquo;Result&amp;rdquo; Types&lt;/h3&gt;
&lt;p&gt;Let&amp;rsquo;s face it, error handling in most SystemVerilog code is bad. The language itself does not provide &amp;ldquo;exceptions&amp;rdquo; or any other architected error handling pattern, so most code just doesn&amp;rsquo;t handle errors. When an error &lt;em&gt;does&lt;/em&gt; happen, most code will either log an error message then give up, or it will log an error and carry on as if nothing happened. From a software engineering perspective, this first off just bad practice, but also can lead to unpredictable behavior following the first error in a simulation.&lt;/p&gt;
&lt;p&gt;We can do better though! Another language that doesn&amp;rsquo;t have exceptions, but does have sum types is &lt;a href=&#34;https://www.rust-lang.org/&#34;&gt;Rust&lt;/a&gt;. In Rust, the error handling problem is implemented using a &lt;code&gt;Result&lt;/code&gt; tagged union type (called &lt;code&gt;enum&lt;/code&gt; in rust). Any function that &lt;em&gt;could&lt;/em&gt; fail returns a &lt;code&gt;Result&amp;lt;T, E&amp;gt;&lt;/code&gt; value, if the function succeeds then an &lt;code&gt;Ok&lt;/code&gt; value is returned with a return value of type &lt;code&gt;T&lt;/code&gt;. If the function fails for some reason, then an &lt;code&gt;Err&lt;/code&gt; value is returned, along with an &lt;code&gt;E&lt;/code&gt; typed value representing the kind of error that occurred.&lt;/p&gt;
&lt;p&gt;The nice thing about this error handling technique is that it requires no additional features from the language (such as exceptions), but provides a consistent way for functions to return errors to their caller in a way &lt;strong&gt;that cannot be ignored&lt;/strong&gt;. The compiler doesn&amp;rsquo;t allow you to use the return value from the function without either handling errors, or at least explicitly ignoring them. In my experience, this pattern works well in Rust, and I think it could be a good pattern for error handling in SystemVerilog.&lt;/p&gt;
&lt;p&gt;Below I show a &amp;ldquo;Result&amp;rdquo; type implemented in SystemVerilog with tagged unions. Because SystemVerilog doesn&amp;rsquo;t support parametrizing tagged union types, we can&amp;rsquo;t create a generic &lt;code&gt;Result&amp;lt;T,E&amp;gt;&lt;/code&gt;type, but a simple macro could be used to automate the creation of result types. In this case, I am declaring the handling code for deserializing a byte stream into a packet where it is necessary to check packet length and a packet CRC, either of which could result in an error.&lt;/p&gt;
&lt;figure class=&#34;no-photoswipe&#34;&gt;
  &lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 1
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 2
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 3
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 4
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 5
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 6
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 7
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 8
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 9
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;10
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;11
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;12
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;13
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;14
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;15
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;16
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;17
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;18
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;19
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;20
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;21
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;22
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;23
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;24
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;25
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;26
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-systemverilog&#34; data-lang=&#34;systemverilog&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;typedef&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; { &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; val1; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; val2; } packet_t;  &lt;span style=&#34;color:#75715e&#34;&gt;// Define a packet type
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;typedef&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;enum&lt;/span&gt; { SIZE_ERR, CRC_ERR } error_e;       &lt;span style=&#34;color:#75715e&#34;&gt;// Define a error type
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// The Result tagged union type
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;typedef&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;union&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;tagged&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  packet_t Ok;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  error_e Err;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;} packet_result_t;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// Deserialize function, returning packet_result_t type
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt; packet_result_t deserialize(&lt;span style=&#34;color:#66d9ef&#34;&gt;byte&lt;/span&gt; data[&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;]);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    packet_t pkt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// Check for errors, returning an error enum value if there is one.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (data.size() &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;16&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;tagged&lt;/span&gt; Err SIZE_ERR;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (compute_crc(data[&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;14&lt;/span&gt;]) &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; data[&lt;span style=&#34;color:#ae81ff&#34;&gt;15&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; taged Err CRC_ERR;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// Extract the values
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    pkt.val1 &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; {&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt;{data[&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;]}};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    pkt.val2 &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; {&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt;{data[&lt;span style=&#34;color:#ae81ff&#34;&gt;8&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;11&lt;/span&gt;]}};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// Return the packet value
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;tagged&lt;/span&gt; Ok pkt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;endfunction&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
  
    &lt;figcaption&gt;&lt;span&gt;&amp;#34;Result&amp;#34; tagged union example.&lt;/span&gt;&lt;/figcaption&gt;
  
&lt;/figure&gt;

&lt;p&gt;The other half of this is how do you actually use the returned result type value. This is done using the &amp;ldquo;pattern matching conditional&amp;rdquo; syntax, as described in section 12.6 of the LRM. There are two forms of pattern matching conditionals, one for case statements, and one for if statements. This example shows using both to handle the &amp;ldquo;result&amp;rdquo; from the previously defined &lt;code&gt;deserialize()&lt;/code&gt; function.&lt;/p&gt;
&lt;figure class=&#34;no-photoswipe&#34;&gt;
  &lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 1
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 2
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 3
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 4
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 5
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 6
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 7
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 8
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 9
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;10
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;11
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;12
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;13
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;14
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;15
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;16
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;17
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;18
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;19
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;20
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;21
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;22
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;23
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;24
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;25
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;26
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;27
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;28
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-systemverilog&#34; data-lang=&#34;systemverilog&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;packet_result_t result;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;result &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; deserialize(bytes);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// If pattern matching syntax. In this case errors are being ignored.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (result &lt;span style=&#34;color:#66d9ef&#34;&gt;matches&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;tagged&lt;/span&gt; Ok .pkt)) &lt;span style=&#34;color:#66d9ef&#34;&gt;begin&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// Use the packet value
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// Inside this context, the `pkt` name can be used to refer to
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// the packet_t typed &amp;#34;Ok&amp;#34; value.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// Case matching syntax. This time we will actually do something with
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;//  the errors.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; (result) &lt;span style=&#34;color:#66d9ef&#34;&gt;matches&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;tagged&lt;/span&gt; Ok .pkt:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;begin&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#75715e&#34;&gt;// Use the packet. Once again `pkt` can be used to refer
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;            &lt;span style=&#34;color:#75715e&#34;&gt;// to the packet_t value.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;tagged&lt;/span&gt; Err .e &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&amp;amp;&lt;/span&gt; e &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; SIZE_ERR:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;begin&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#75715e&#34;&gt;// Handle specifically the packet size error condition.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;tagged&lt;/span&gt; Err .e:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;begin&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#75715e&#34;&gt;// Handle any other error value. Once again the `e` value
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;            &lt;span style=&#34;color:#75715e&#34;&gt;// can be used to determine the error type.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;endcase&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
  
    &lt;figcaption&gt;&lt;span&gt;Example showing how the result of the deserialize() function can be used.&lt;/span&gt;&lt;/figcaption&gt;
  
&lt;/figure&gt;

&lt;h3 id=&#34;transaction-packet-or-opcode-subtypes&#34;&gt;Transaction, Packet, or Opcode subtypes&lt;/h3&gt;
&lt;p&gt;In design verification a common thing to do is to declare a class that represents a packet, opcode, or some other kind of &amp;ldquo;transaction&amp;rdquo;. These transaction classes contain variables that hold data from fields of the packet, or operands of the opcode, but what do you do when the transaction can have a different set of data values, depending on the type of transaction. In my experience I have seen two approaches used, either the transaction class contains a superset of all possible fields for the transaction, or sub-classes of the primary transaction type are declared for each transaction format, containing only the valid fields. The problem with including the super-set of fields is the user has to know which fields are valid in a transaction at any given time, and there is nothing to stop you from using an invalid field by mistake. On the other hand, declaring sub-classes can be very verbose, and requires a lot of explicit casts to work with values of the transaction.&lt;/p&gt;
&lt;p&gt;However, tagged unions give us another option. As an example (inspired by one of the tagged union examples the SystemVerilog LRM), say we wanted a transaction that represents a CPU instruction where each instruction format has a different set of operands. We could define the instruction using a class that contains an anonymous tagged union as shown below:&lt;/p&gt;
&lt;figure class=&#34;no-photoswipe&#34;&gt;
  &lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 1
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 2
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 3
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 4
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 5
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 6
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 7
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 8
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 9
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;10
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;11
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;12
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;13
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;14
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;15
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;16
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;17
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;18
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;19
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;20
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;21
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-systemverilog&#34; data-lang=&#34;systemverilog&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; Instruction &lt;span style=&#34;color:#66d9ef&#34;&gt;extends&lt;/span&gt; uvm_sequence_item;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// Main opcode definition
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;union&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;tagged&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;// Binary arethmatic instruction format supports add, subtract, multiply, and divde
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;// opcodes, with three operands, two source registers and one destination register
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;enum&lt;/span&gt; { ADD, SUB, MUL, DIV } opcode,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;bit&lt;/span&gt; [&lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;] r1, r2, rdest;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        } BIN_FMT
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;// Jump format instruction has a single destination literal operand with three
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;// different opcodes.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;enum&lt;/span&gt; { JMP, JEQ, JNE } opcode;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;bit&lt;/span&gt; [&lt;span style=&#34;color:#ae81ff&#34;&gt;9&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;] target;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        } JMP_FMT;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    } format;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// Additional metadata fields can still be added to the transaction class.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;time&lt;/span&gt; start_time;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;endclass&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; Instruction
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
  
    &lt;figcaption&gt;&lt;span&gt;Example of using tagged unions to express transacion with different field formats.&lt;/span&gt;&lt;/figcaption&gt;
  
&lt;/figure&gt;

&lt;p&gt;With this construction, the &lt;code&gt;Instruction&lt;/code&gt; transaction class can hold all the operands for all instruction formats, but the compiler will only allow us to reference the fields for the instruction format actually used by the current value of the &lt;code&gt;Instruction&lt;/code&gt; transaction. This sounds similar to the sub-class approach, however where with a sub-class implementation you would need to cast the &lt;code&gt;Instruction&lt;/code&gt; to a &lt;code&gt;BinFmtInstruction&lt;/code&gt; to access the &lt;code&gt;r1&lt;/code&gt; field (for example), in this implementation it is possible to refer to any field without casts as long as the format is correct. For example if we have already checked that &lt;code&gt;format&lt;/code&gt; is &lt;code&gt;BIN_FMT&lt;/code&gt; the expression &lt;code&gt;inst.BIN_FMT.rdest&lt;/code&gt; will reference the &lt;code&gt;rdest&lt;/code&gt; value of the instruction with no casts.&lt;/p&gt;
&lt;p&gt;Is this actually better than the alternatives though? I believe it is a significant improvement over defining a transaction with a super-set of fields (the most common approach), since it ensures correctness when referencing the transaction fields. I am not sure it&amp;rsquo;s that much better than defining class sub-types for each packet format, since both require that you explicitly check the transaction format before you can reference values. However, I think the tagged union implementation would make the code easier to read with fewer &lt;code&gt;$cast&lt;/code&gt; calls and variables of different subtypes hanging around.&lt;/p&gt;
&lt;h3 id=&#34;configuration&#34;&gt;Configuration&lt;/h3&gt;
&lt;p&gt;The final application where there could be real benefits from using tagged unions is in configuring sequences and components. Particularly where there is some mode setting where each mode has a different set of options that can be configured. Take the example of a sequence which generates transactions with a configurable traffic pattern. This might normally be implemented like the following:&lt;/p&gt;
&lt;figure class=&#34;no-photoswipe&#34;&gt;
  &lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;1
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;2
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;3
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;4
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;5
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;6
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;7
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;8
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;9
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-systemverilog&#34; data-lang=&#34;systemverilog&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;typedef&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;enum&lt;/span&gt; {PERIODIC, RAND, BURST} traffic_pattern_t;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; traffic_seq &lt;span style=&#34;color:#66d9ef&#34;&gt;extends&lt;/span&gt; uvm_sequence;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    traffic_pattern_t pattern.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;rand&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;time&lt;/span&gt; periodic_interval;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;rand&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;time&lt;/span&gt; rand_min;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;rand&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;time&lt;/span&gt; rand_max;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;rand&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;time&lt;/span&gt; burst_interval;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;rand&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;time&lt;/span&gt; burst_duration;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;endclass&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; traffic_seq
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
  
    &lt;figcaption&gt;&lt;span&gt;Traditional implementation of a configurable traffic sequence.&lt;/span&gt;&lt;/figcaption&gt;
  
&lt;/figure&gt;

&lt;p&gt;In this implementation, the &lt;code&gt;periodic_interval&lt;/code&gt; variable is only valid when &lt;code&gt;pattern == PERIODIC&lt;/code&gt;. Likewise, the value of &lt;code&gt;rand_min&lt;/code&gt; and &lt;code&gt;rand_max&lt;/code&gt; are only used when &lt;code&gt;pattern == RAND&lt;/code&gt;. At best it is confusing that you can set &lt;code&gt;periodic_interval&lt;/code&gt; when pattern is set to &lt;code&gt;BURST&lt;/code&gt;. A better way you could implement the same concept with tagged unions would look like the following:&lt;/p&gt;
&lt;figure class=&#34;no-photoswipe&#34;&gt;
  &lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;1
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;2
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;3
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;4
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;5
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;6
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;7
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-systemverilog&#34; data-lang=&#34;systemverilog&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; traffic_seq;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;union&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;tagged&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; { &lt;span style=&#34;color:#66d9ef&#34;&gt;time&lt;/span&gt; interval;                } PERIODIC;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; { &lt;span style=&#34;color:#66d9ef&#34;&gt;time&lt;/span&gt; min;      &lt;span style=&#34;color:#66d9ef&#34;&gt;time&lt;/span&gt; max;      } RAND;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; { &lt;span style=&#34;color:#66d9ef&#34;&gt;time&lt;/span&gt; interval; &lt;span style=&#34;color:#66d9ef&#34;&gt;time&lt;/span&gt; duration; } BURST;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    } pattern;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;endclass&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; traffic_seq
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
  
    &lt;figcaption&gt;&lt;span&gt;Configuration traffic pattern sequence using tagged unions.&lt;/span&gt;&lt;/figcaption&gt;
  
&lt;/figure&gt;

&lt;p&gt;With the tagged union implementation the &lt;code&gt;min&lt;/code&gt; and &lt;code&gt;max&lt;/code&gt; values only exist (from the compiler&amp;rsquo;s perspective) when &lt;code&gt;pattern == RAND&lt;/code&gt;. Additionally you cannot set pattern &lt;em&gt;without&lt;/em&gt; setting it&amp;rsquo;s parameters. As an to set the pattern to &lt;code&gt;BURST&lt;/code&gt; you would use an expression like:&lt;/p&gt;
&lt;figure class=&#34;no-photoswipe&#34;&gt;
  &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-systemverilog&#34; data-lang=&#34;systemverilog&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;seq.pattern &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;tagged&lt;/span&gt; BURST &amp;#39;{interval: &lt;span style=&#34;color:#ae81ff&#34;&gt;100&lt;/span&gt;ns, duration: &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;ns};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  
&lt;/figure&gt;

&lt;p&gt;I like this tagged union approach because not only is the assignment expression fairly concise and explicit, but it eliminates a whole class of errors and confusions. The configuration parameters for given traffic pattern type can only be accessed within the context of that pattern. There is no way to accidentally set &lt;code&gt;periodic_internval&lt;/code&gt; instead of &lt;code&gt;burst_interval&lt;/code&gt;. This tagged union design pattern could be applied to any use case where there is a setting where each option has it&amp;rsquo;s own parameters. For example you might use this for a configuration that controls a random distribution modes (think normal, uniform, geometric, etc.) where each distribution has it&amp;rsquo;s own unique arguments.&lt;/p&gt;
&lt;h2 id=&#34;wrap-up&#34;&gt;Wrap Up&lt;/h2&gt;
&lt;p&gt;As I mentioned at the beginning, the potential uses for tagged unions in SystemVerilog has been something I couldn&amp;rsquo;t get out of my mind for a few months. Although I have not been able to actually do a lot of work with them (due to Cadence lacking any kind of support), I think there are several good applications for tagged unions which would improve the readability and correctness of verification code, through syntax and compile time checks. Unfortunately, while tagged unions appear to have a lot of advantages, lacking tool support and poor syntax ergonomics sadly make it pretty much a non-starter from a practical perspective.&lt;/p&gt;
&lt;p&gt;If anyone has actually used SystemVerilog tagged unions, I would love to know how you used them and how they worked out.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Building A Picture Frame From Mars</title>
      <link>https://prbs23.com/blog/posts/picture-frame-from-mars/</link>
      <pubDate>Sun, 14 Nov 2021 13:16:20 -0700</pubDate>
      <author>prbs23@prbs23.com (prbs23)</author>
      <guid>https://prbs23.com/blog/posts/picture-frame-from-mars/</guid>
      <description>&lt;p&gt;This whole project started when I happened across the &lt;a href=&#34;https://mars.nasa.gov/mars2020/multimedia/raw-images/&#34;&gt;NASA Perseverance Raw Image Library&lt;/a&gt; one day. Something about the constantly varying combination of images: some with scientific purposes, some for navigation, and some of the rover itself, along with the fact that they were &lt;em&gt;FROM MARS&lt;/em&gt; kept me coming back to the page to see what Curiosity had been up to lately. This eventually lead to the idea of having a digital picture frame which would cycle through the latest raw images from the Perseverance rover. So that&amp;rsquo;s what I set out to build.&lt;/p&gt;


&lt;div class=&#34;box &#34; style=&#34;max-width:75%&#34;&gt;
  &lt;figure  itemprop=&#34;associatedMedia&#34; itemscope itemtype=&#34;http://schema.org/ImageObject&#34;&gt;
    &lt;div class=&#34;img&#34;&gt;
      &lt;img itemprop=&#34;thumbnail&#34; src=&#34;https://prbs23.com/blog/blog/posts/picture-frame-from-mars/completed_photo_frame.jpg&#34; alt=&#34;Finished Perseverance Digital Picture Frame&#34;/&gt;
      &lt;a href=&#34;https://prbs23.com/blog/blog/posts/picture-frame-from-mars/completed_photo_frame.jpg&#34; itemprop=&#34;contentUrl&#34;&gt;&lt;/a&gt;
    &lt;/div&gt;
      &lt;figcaption&gt;
          &lt;p&gt;
            Finished Perseverance Digital Picture Frame
            
          &lt;/p&gt;
      &lt;/figcaption&gt;
  &lt;/figure&gt;
&lt;/div&gt;

&lt;h2 id=&#34;the-hardware&#34;&gt;The Hardware&lt;/h2&gt;
&lt;p&gt;To start with, I would need a digital picture frame with internet access. There were two main directions I could have taken here; build a picture frame from scratch, or somehow modify a commercial frame. On one hand I could connect a Raspberry Pi to a large LCD panel and stick it in a picture frame, this would give me a very customizable platform to develop on, at the cost of some extra effort and being a less integrated solution. On the other hand, I could just buy an off the shelf Wi-Fi enabled digital picture frame and figure out how to write my own software/firmware for it. This would be easier from a hardware perspective, but I depending on what hardware and software ran on the picture frame it could make programming for it more difficult.&lt;/p&gt;
&lt;p&gt;In the end I decided to use an off the shelf Wi-Fi photo frame, mainly because of cost, I was able to buy an full integrated picture frame for less than the cost of a just the LCD panel required to build my own. When I was comparing the Wi-Fi picture frames on the market I found something interesting, almost all of them used one of two platforms to enable the user to upload pictures to the frame: &lt;a href=&#34;https://play.google.com/store/apps/details?id=com.idwell.ourphoto&amp;amp;hl=en_US&amp;amp;gl=US&#34;&gt;OurPhoto&lt;/a&gt; or &lt;a href=&#34;https://frameo.net/&#34;&gt;Frameo&lt;/a&gt;. From what I could learn, both these platforms provide smart picture frame firmware to various manufactures which integrate with their platforms. While I was unable to find any useful information about the content of this firmware, the fact that it was designed to run across many different hardware models gave me some confidence that I wasn&amp;rsquo;t going to to find a highly specialized or low level firmware in these devices. I ended up buying an &lt;a href=&#34;https://www.amazon.com/dp/B083SH697H&#34;&gt;AKImart 10.1 Inch Smart WiFi Digital Photo Frame&lt;/a&gt; for a little over $100, as it struck a decent balance between size and being cheap enough I was okay with potentially bricking it.&lt;/p&gt;
&lt;h3 id=&#34;its-an-android-system&#34;&gt;&amp;ldquo;It&amp;rsquo;s an ANDROID system&amp;rdquo;&lt;/h3&gt;
&lt;p&gt;

&lt;div class=&#34;box floatright&#34; style=&#34;max-width:50%&#34;&gt;
  &lt;figure class=&#34;floatright&#34; itemprop=&#34;associatedMedia&#34; itemscope itemtype=&#34;http://schema.org/ImageObject&#34;&gt;
    &lt;div class=&#34;img&#34;&gt;
      &lt;img itemprop=&#34;thumbnail&#34; src=&#34;https://prbs23.com/blog/blog/posts/picture-frame-from-mars/android_about_tablet.jpg&#34; alt=&#34;My digital picture frame turned out to be running Android 6.0.1&#34;/&gt;
      &lt;a href=&#34;https://prbs23.com/blog/blog/posts/picture-frame-from-mars/android_about_tablet.jpg&#34; itemprop=&#34;contentUrl&#34;&gt;&lt;/a&gt;
    &lt;/div&gt;
      &lt;figcaption&gt;
          &lt;p&gt;
            My digital picture frame turned out to be running Android 6.0.1
            
          &lt;/p&gt;
      &lt;/figcaption&gt;
  &lt;/figure&gt;
&lt;/div&gt;

Overall there was very little information online about what hardware I could expect to find in the picture frame, so I didn&amp;rsquo;t really know what I was getting myself into. My best guess was I would find some kind of ARM single board computer, running either a customized Linux OS or a specialized Android ROM. It didn&amp;rsquo;t take long to figure out though, because when I first turned on my picture frame, the first thing I was greeted with was an Android setup wizard. This could either of been a really good thing (lots of development resources) or a bad thing (Android can be locked down well if properly configured).&lt;/p&gt;
&lt;p&gt;The &amp;ldquo;Digital Picture Frame&amp;rdquo; that I bought turned out to essentially be a stripped down tablet without a battery running Android 6.0.1. While the OS was configured such one couldn&amp;rsquo;t escape the Frameo &amp;ldquo;Frame&amp;rdquo; app and use it as a normal Android device, fortunately the &lt;a href=&#34;https://developer.android.com/studio/command-line/adb&#34;&gt;ADB USB debugging interface&lt;/a&gt; was left enabled, and even had root permissions. From the ADB shell I could install and launch any app I wanted, so all I needed now was an Android app that would show the latest pictures from Perseverance.&lt;/p&gt;
&lt;h2 id=&#34;perseverance-raw-image-api&#34;&gt;Perseverance Raw Image API&lt;/h2&gt;
&lt;p&gt;Now that I knew I should be able to write my own software for picture frame, I needed to figure out how to actually get the latest pictures from the raw image library. Initially, I was hoping to find public API of some kind to retrieve the pictures, maybe a simple RSS would be nice. NASA does in fact have several &lt;a href=&#34;https://api.nasa.gov/&#34;&gt;open APIs&lt;/a&gt; for various programs, they even have a &lt;a href=&#34;https://api.nasa.gov#mars-rover-photos&#34;&gt;Mars Rover Photos API&lt;/a&gt;. Unfortunately though this API does includes images from many previous mars rover missions, including Curiosity rover mission, it does not provide access to the Perseverance images.  While there was no public API for me to use in the end, I did eventually find that the &lt;a href=&#34;https://mars.nasa.gov/mars2020/multimedia/raw-images/&#34;&gt;Perseverance Raw Image Library&lt;/a&gt; webpage makes requests to an undocumented but open API to retrieve a list of images to display.&lt;/p&gt;
&lt;p&gt;Fortunately, the API used by the raw image library page was fairly simple to reverse engineer, at least as far as was required for my purposes. All requests were sent to &lt;code&gt;https://mars.nasa.gov/rss/api/&lt;/code&gt; with various query parameters that controlled the type of request and content returned, which in all cases was a JSON object. The first step was to understand how the various query parameters worked. There were some query parameters that were fixed, in all the requests I could observe:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;feed=raw_images&lt;/code&gt;&lt;br&gt;
Presumably there are multiple data feeds that could be served through this API.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;feedtype=json&lt;/code&gt;&lt;br&gt;
The data returned by the API was json encoded, so this makes sense, but even an obvious alternative such as &lt;code&gt;feedtype=xml&lt;/code&gt; resulted in a 404.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ver=1.2&lt;/code&gt;&lt;br&gt;
Likely the API version number.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;category=mars2020,ingenuity&lt;/code&gt;&lt;br&gt;
The existence of this argument implies there could be other raw image feeds, if only we knew the right string. Once again, I have yet to find other valid categories, and no way of listing the available categories.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Presumably there are alternate valid values for these parameters, but I was never able to find any that did not return a 404 error code. In addition to these fixed parameters, there were two parameters that controlled the format of JSON object, resulting in three different message formats, as indicated by the &lt;code&gt;type&lt;/code&gt; field in the response.&lt;/p&gt;
&lt;h3 id=&#34;latest-images-summary&#34;&gt;Latest Images Summary&lt;/h3&gt;
&lt;p&gt;When &lt;code&gt;latest=true&lt;/code&gt; is included in the request query parameters, a latest image summary object is returned, as indicated by a &lt;code&gt;mars2020_ingenuity-latest-images-1.2&lt;/code&gt; value in the &lt;code&gt;type&lt;/code&gt; field:
&lt;figure class=&#34;no-photoswipe&#34;&gt;
  &lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 1
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 2
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 3
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 4
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 5
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 6
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 7
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 8
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 9
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;10
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;11
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;12
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;13
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;14
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;type&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;mars2020_ingenuity-latest-images-1.2&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;total&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;161829&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;new_count&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;389&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;latest_sol&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;258&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;latest&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;2021-11-11T15:49:19Z&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;sol_count&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;55&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;latest_sols&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; [
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;258&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;257&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;256&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;208&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ],
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
  
    &lt;figcaption&gt;&lt;span&gt;https://mars.nasa.gov/rss/api/?feed=raw_images&amp;amp;category=mars2020,ingenuity&amp;amp;feedtype=json&amp;amp;ver=1.2&amp;amp;latest=true&lt;/span&gt;&lt;/figcaption&gt;
  
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;The content of this response message does not appear to change with any other query parameters. The content of the message gives a few useful pieces of information:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;total&lt;/code&gt;&lt;br&gt;
Appears to be a total number of images available through this API. It does not reflect the total number images in the Perseverance/Ingenuity category.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;new_count&lt;/code&gt;&lt;br&gt;
Number of &amp;ldquo;new&amp;rdquo; images, which appears to be the number of images published in the last 24 hours.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;latest_sol&lt;/code&gt;&lt;br&gt;
The most recent &amp;ldquo;sol&amp;rdquo; (number of mars solar days for the rover since the beginning of it&amp;rsquo;s mission) for which images have been published.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;latest&lt;/code&gt;&lt;br&gt;
UTC time that the image was received on earth from the rover. Interestingly it appears that images can be buffered for a surprisingly long time before being received, I have seen images with almost two (earth) months between being captured and received.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sol_count&lt;/code&gt;&lt;br&gt;
Based on the name and values returned, this appears to be a count of mars solar days, but it&amp;rsquo;s not clear what it represents.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;latest_sols&lt;/code&gt;&lt;br&gt;
List of &amp;ldquo;sols&amp;rdquo; for which pictures have been published in the last 24 hours.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;image-detail-response&#34;&gt;Image Detail Response&lt;/h3&gt;
&lt;p&gt;When an &lt;code&gt;id=&lt;/code&gt; query parameter is included in the request, an image detail response object is returned, corresponding to the image with the given unique id. This response format for this response is indicated by the &lt;code&gt;type&lt;/code&gt; value of &lt;code&gt;mars2020-imagedetail-1.2&lt;/code&gt;.
&lt;figure class=&#34;no-photoswipe&#34; style=&#34;--max-figure-height:300px;&#34;&gt;
  &lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 1
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 2
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 3
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 4
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 5
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 6
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 7
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 8
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 9
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;10
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;11
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;12
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;13
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;14
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;15
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;16
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;17
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;18
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;19
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;20
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;21
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;22
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;23
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;24
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;25
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;26
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;27
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;28
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;29
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;30
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;31
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;32
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;33
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;34
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;35
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;36
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;37
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;38
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;39
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;40
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;41
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;42
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;43
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;44
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;45
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;46
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;47
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;image&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; [
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;extended&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;mastAz&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;21.5952&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;mastEl&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;24.5965&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;sclk&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;689864742.333&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;scaleFactor&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;4&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;xyz&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;(0.0,0.0,0.0)&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;subframeRect&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;(1,1,5120,3840)&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;dimension&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;(1280,960)&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;link_related_sol&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;https://mars.nasa.gov/mars2020/multimedia/raw-images/?sol=258&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;sol&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;258&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;attitude&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;(0.81634,-0.0556483,-0.000426989,0.574885)&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;json_link_related_sol&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;https://mars.nasa.gov/rss/api/?feed=raw_images&amp;amp;category=mars2020,ingenuity&amp;amp;feedtype=json&amp;amp;sol=258&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;image_files&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;medium&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;https://mars.nasa.gov/mars2020-raw-images/pub/ods/surface/sol/00258/ids/edr/browse/ncam/NLF_0258_0689864724_675ECM_N0080000NCAM00514_01_295J01_800.jpg&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;small&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;https://mars.nasa.gov/mars2020-raw-images/pub/ods/surface/sol/00258/ids/edr/browse/ncam/NLF_0258_0689864724_675ECM_N0080000NCAM00514_01_295J01_320.jpg&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;full_res&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;https://mars.nasa.gov/mars2020-raw-images/pub/ods/surface/sol/00258/ids/edr/browse/ncam/NLF_0258_0689864724_675ECM_N0080000NCAM00514_01_295J01.png&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;large&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;https://mars.nasa.gov/mars2020-raw-images/pub/ods/surface/sol/00258/ids/edr/browse/ncam/NLF_0258_0689864724_675ECM_N0080000NCAM00514_01_295J01_1200.jpg&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;imageid&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;NLF_0258_0689864724_675ECM_N0080000NCAM00514_01_295J&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;camera&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;filter_name&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;UNK&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;camera_vector&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;(0.8452750616932372,0.3358633696321663,-0.41557895401333894)&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;camera_model_component_list&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;(0.972477,0.396478,-2.02505);(0.843847,0.347228,-0.40911);(265.584,909.072,-265.014);(689.368,283.332,476.213);(0.843346,0.348554,-0.409015);(1.736e-06,0.0501396,-0.0171254);(-8e-09,1e-08,-2.9e-08);2.0;0.0&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;camera_position&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;(0.972477,0.396478,-2.02505)&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;instrument&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;NAVCAM_LEFT&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;camera_model_type&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;CAHVORE&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;caption&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;NASA&amp;#39;s Mars Perseverance rover acquired this image using its onboard Left Navigation Camera (Navcam). The camera is located high on the rover&amp;#39;s mast and aids in driving. \n\nThis image was acquired on Nov. 11, 2021 (Sol 258) at the local mean solar time of 18:02:21.&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;sample_type&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Full&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;date_taken_mars&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Sol-00258M18:02:21.470&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;credit&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;NASA/JPL-Caltech&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;date_taken_utc&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;2021-11-11T01:10:13.211&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;link&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;https://mars.nasa.gov/mars2020/multimedia/raw-images/?id=NLF_0258_0689864724_675ECM_N0080000NCAM00514_01_295J&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;link_related_camera&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;https://mars.nasa.gov/mars2020/multimedia/raw-images/?camera=NAVCAM_LEFT&amp;amp;sol=258&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;drive&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;0&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;title&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Mars Perseverance Sol 258: Left Navigation Camera (Navcam)&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;site&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;8&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;date_received&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;2021-11-11T08:34:42Z&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ],
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;type&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;mars2020_ingenuity-imagedetail-1.2&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;mission&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;mars2020,ingenuity&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
  
    &lt;figcaption&gt;&lt;span&gt;https://mars.nasa.gov/rss/api/?feed=raw_images&amp;amp;category=mars2020,ingenuity&amp;amp;ver=1.2&amp;amp;feedtype=json&amp;amp;id=NLF_0258_0689864724_675ECM_N0080000NCAM00514_01_295J&lt;/span&gt;&lt;/figcaption&gt;
  
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;image&lt;/code&gt; object contains a lot of detailed information about the specific image. For my purpose of just displaying images the images I found the following images useful:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;image_files&lt;/code&gt;&lt;br&gt;
Object containing URLs to four differently scaled versions of the image.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sol&lt;/code&gt;&lt;br&gt;
Mission solar day number when the image was captured.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;date_taken_utc&lt;/code&gt;&lt;br&gt;
The UTC time-stamp of when the image was captured.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;date_received&lt;/code&gt;&lt;br&gt;
UTC time-stamp of when the image was received by NASA.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;title&lt;/code&gt;&lt;br&gt;
Short title for the image. This usually contains the sol that the image was captured and the name of the camera used to capture the image.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;caption&lt;/code&gt;&lt;br&gt;
Long form auto-generated caption describing the image.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;images-list-response&#34;&gt;Images List Response&lt;/h3&gt;
&lt;p&gt;Finally if neither &lt;code&gt;latest=true&lt;/code&gt; or &lt;code&gt;id=&lt;/code&gt; query parameters are included in the request an images list response, as indicated by the &lt;code&gt;mars2020_ingenuity-images-list-1.2&lt;/code&gt; &lt;code&gt;type&lt;/code&gt; value is returned. I found that this type of request responded to a few different query parameters, to either control the amount of data returned or filter the list of returned images. Below are the parameters that I was able to reverse engineer:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;num=&amp;lt;Integer&amp;gt;&lt;/code&gt;&lt;br&gt;
Number of images to return in this request. There appears to be hard maximum of 100 image per request.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;page=&amp;lt;Integer&amp;gt;&lt;/code&gt;&lt;br&gt;
Page number of results to return. By default (&lt;code&gt;page=0&lt;/code&gt;) the returned image list contains the first &lt;code&gt;num&lt;/code&gt; images that match the given filters. For non-zero values of &lt;code&gt;page&lt;/code&gt; the API returns &lt;code&gt;num&lt;/code&gt; pictures starting at offset &lt;code&gt;num * page&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;order=&amp;lt;String&amp;gt;&lt;/code&gt;&lt;br&gt;
String value controlling the order of returned images. The only valid values I have found are &lt;code&gt;sol desc&lt;/code&gt; (ordered from newest to oldest by mission solar day number), and &lt;code&gt;sol asc&lt;/code&gt; (ordered from oldest to newest by sol number).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sol=&amp;lt;Integer&amp;gt;&lt;/code&gt;&lt;br&gt;
Filter returned image list to a single mars solar day number.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;search=&amp;lt;String&amp;gt;&lt;/code&gt;&lt;br&gt;
Filters the returned image list based on the camera used to capture the image. This is string of pipe (&lt;code&gt;|&lt;/code&gt;) separated camera identifiers. The response to this query includes a data structure that lists the valid camera identifiers, but the current list appears to be: &lt;code&gt;HELI_NAV&lt;/code&gt; &lt;code&gt;HELI_RTE&lt;/code&gt;, &lt;code&gt;NAVCAM_LEFT&lt;/code&gt;, &lt;code&gt;NAVCAM_RIGHT&lt;/code&gt;, &lt;code&gt;FRONT_HAZCAM_LEFT_A&lt;/code&gt;, &lt;code&gt;FRONT_HAZCAM_LEFT_B&lt;/code&gt;, &lt;code&gt;FRONT_HAZCAM_RIGHT_A&lt;/code&gt;, &lt;code&gt;FRONT_HAZCAM_RIGHT_B&lt;/code&gt;, &lt;code&gt;REAR_HAZCAM_LEFT&lt;/code&gt;, &lt;code&gt;REAR_HAZCAM_RIGHT&lt;/code&gt;, &lt;code&gt;CACHECAM&lt;/code&gt;, &lt;code&gt;MCZ_LEFT&lt;/code&gt;, &lt;code&gt;MCZ_RIGHT&lt;/code&gt;, &lt;code&gt;SKYCAM&lt;/code&gt;, &lt;code&gt;PIXL_MCC&lt;/code&gt;, &lt;code&gt;SHERLOC_WATSON&lt;/code&gt;, &lt;code&gt;SHERLOC_ACI&lt;/code&gt;, &lt;code&gt;SUPERCAM_RMI&lt;/code&gt;, &lt;code&gt;EDL_PUCAM1&lt;/code&gt;, &lt;code&gt;EDL_PUCAM2&lt;/code&gt;, &lt;code&gt;EDL_DDCAM&lt;/code&gt;, &lt;code&gt;EDL_RUCAM&lt;/code&gt;, &lt;code&gt;LCAM&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;condition_2=&amp;lt;String&amp;gt;&lt;/code&gt;&lt;br&gt;
Generally a starting date filter. This field can either filter based on day the image was taken using the form  &lt;code&gt;&amp;lt;yyyy-MM-dd&amp;gt;:date_taken:gte&lt;/code&gt;, or filter based on the time that the image was received using the form &lt;code&gt;&amp;lt;yyyy-MM-dd&#39;T&#39;HH:mm:ss.SSSSSSZ&amp;gt;:date_received:gte&lt;/code&gt; when used in conjunction with a &lt;code&gt;condition_3&lt;/code&gt; &lt;code&gt;sol&lt;/code&gt; filter parameter.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;condition_3=&amp;lt;String&amp;gt;&lt;/code&gt;&lt;br&gt;
Either an end date or sol number filter. With no &lt;code&gt;condition_2&lt;/code&gt; parameter specified, or when &lt;code&gt;condition_2&lt;/code&gt; uses the &amp;ldquo;date_taken&amp;rdquo; format, this parameter is an end date filter using the form &lt;code&gt;&amp;lt;yyyy-MM-dd&amp;gt;:date_take:lt&lt;/code&gt;. When &lt;code&gt;condition_2&lt;/code&gt; is a &amp;ldquo;date_received&amp;rdquo; filter, this parameter can be a sol number filter of the form: &lt;code&gt;&amp;lt;comma separated list of sol numbers&amp;gt;:sol:in&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;While it would seem that the &lt;code&gt;condition_2&lt;/code&gt; and &lt;code&gt;condition_3&lt;/code&gt; parameters appear as if they could provide more generic filtering features, they appear to be locked down to only these use cases on the server side. The response to this type of request looks like the following (lists abbreviated):
&lt;figure class=&#34;no-photoswipe&#34; style=&#34;--max-figure-height:300px;&#34;&gt;
  &lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 1
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 2
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 3
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 4
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 5
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 6
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 7
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 8
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 9
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;10
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;11
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;12
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;13
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;14
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;15
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;16
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;17
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;18
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;19
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;20
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;21
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;22
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;23
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;24
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;25
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;26
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;27
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;28
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;29
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;30
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;31
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;32
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;33
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;34
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;35
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;36
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;37
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;38
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;39
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;40
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;41
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;42
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;43
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;44
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;45
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;46
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;47
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;48
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;49
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;50
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;51
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;52
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;53
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;54
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;55
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;56
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;57
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;nav&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; [
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;checkboxes&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; [
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;value&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;HELI_NAV&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;label&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Navigation Camera&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      ],
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;order&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;4&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;name&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Mars Helicopter Tech Demo Cameras&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;about_text&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Cameras onboard the &amp;lt;a href=&amp;#39;https://mars.nasa.gov/technology/helicopter/&amp;#39;&amp;gt;Ingenuity Mars Helicopter&amp;lt;/a&amp;gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ],
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;images&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; [
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;extended&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; {&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;mastAz&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;UNK&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;mastEl&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;UNK&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;sclk&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;666952979.177&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;scaleFactor&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;4&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;xyz&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;(0.0,0.0,0.0)&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;subframeRect&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;(1,1,1280,960)&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;dimension&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;(1280,960)&amp;#34;&lt;/span&gt;},
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;sol&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;attitude&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;(1.0,0.0,0.0,0.0)&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;image_files&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;medium&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;https://mars.nasa.gov/mars2020-raw-images/pub/ods/surface/sol/00000/ids/edr/browse/fcam/FLR_0000_0666952977_663ECM_N0010044AUT_04096_00_2I3J02_800.jpg&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;small&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;https://mars.nasa.gov/mars2020-raw-images/pub/ods/surface/sol/00000/ids/edr/browse/fcam/FLR_0000_0666952977_663ECM_N0010044AUT_04096_00_2I3J02_320.jpg&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;full_res&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;https://mars.nasa.gov/mars2020-raw-images/pub/ods/surface/sol/00000/ids/edr/browse/fcam/FLR_0000_0666952977_663ECM_N0010044AUT_04096_00_2I3J02.png&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;large&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;https://mars.nasa.gov/mars2020-raw-images/pub/ods/surface/sol/00000/ids/edr/browse/fcam/FLR_0000_0666952977_663ECM_N0010044AUT_04096_00_2I3J02_1200.jpg&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;imageid&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;FLR_0000_0666952977_663ECM_N0010044AUT_04096_00_2I3J02&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;camera&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;filter_name&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;UNK&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;camera_vector&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;(0.6926460219832632,-0.7044446294451989,-0.15491692056253062)&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;camera_model_component_list&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;(1.10353,-0.008945,-0.729124);(0.884935,-0.17181,0.432865);(651.291,418.924,318.224);(186.623,-81.6605,689.135);(0.885293,-0.171227,0.432363);(1e-06,0.00889,-0.006754);(-0.006127,0.010389,0.004541);2.0;0.0&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;camera_position&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;(1.10353,-0.008945,-0.729124)&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;instrument&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;FRONT_HAZCAM_LEFT_A&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;camera_model_type&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;CAHVORE&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;caption&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;NASA&amp;#39;s Mars Perseverance rover acquired this image of the area in front of it using its onboard Front Left Hazard Avoidance Camera A. \n\nThis image was acquired on Feb. 18, 2021 (Sol 0) at the local mean solar time of 15:53:58.&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;sample_type&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Full&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;date_taken_mars&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Sol-00000M15:53:58.302&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;credit&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;NASA/JPL-Caltech&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;date_taken_utc&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;2021-02-18T20:44:29.175&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;json_link&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;https://mars.nasa.gov/rss/api/?feed=raw_images&amp;amp;category=mars2020,ingenuity&amp;amp;feedtype=json&amp;amp;id=FLR_0000_0666952977_663ECM_N0010044AUT_04096_00_2I3J02&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;link&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;https://mars.nasa.gov/mars2020/multimedia/raw-images/?id=FLR_0000_0666952977_663ECM_N0010044AUT_04096_00_2I3J02&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;drive&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;44&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;title&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Mars Perseverance Sol 0: Front Left Hazard Avoidance Camera (Hazcam)&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;site&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;date_received&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;2021-02-22T20:06:53Z&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ],
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;per_page&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;3&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;total_results&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;67201&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;type&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;mars2020_ingenuity-images-list-1.2&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;page&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;mission&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;mars2020,ingenuity&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;total_images&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;162120&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
  
    &lt;figcaption&gt;&lt;span&gt;https://mars.nasa.gov/rss/api/?feed=raw_images&amp;amp;category=mars2020,ingenuity&amp;amp;feedtype=json&amp;amp;ver=1.2&amp;amp;num=3&amp;amp;page=0&amp;amp;&amp;amp;order=sol&amp;#43;asc&lt;/span&gt;&lt;/figcaption&gt;
  
&lt;/figure&gt;

Depending on how many images are requested, these responses can be large, but the main fields of interest are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;nav&lt;/code&gt;&lt;br&gt;
Structure containing the valid camera identifiers for the search query parameter. Since this structure appears to be used to render the filter UI on the raw image library webpage, it not only includes the camera identifiers, it also includes a human readable name for the camera.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;images&lt;/code&gt;&lt;br&gt;
List of image details objects for images matching the query filters. This uses the same data structure as the &lt;code&gt;image&lt;/code&gt; object in the image details response.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;per_page&lt;/code&gt;&lt;br&gt;
Number of images actually returned per &amp;ldquo;page&amp;rdquo; by this request. Should match the &lt;code&gt;num&lt;/code&gt; query parameter, unless it&amp;rsquo;s greater than the hard limit of 100.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;page&lt;/code&gt;&lt;br&gt;
The &amp;ldquo;page&amp;rdquo; number of images returned in this request. This should be the same as the &lt;code&gt;page&lt;/code&gt; query parameter, if specified.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;total_results&lt;/code&gt;&lt;br&gt;
Total number of images that match the filters given in the request.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;the-customized-picture-frame-app&#34;&gt;The Customized Picture Frame App&lt;/h2&gt;
&lt;p&gt;Once I determined that the picture frame was running Android with an open ADB shell, I knew it should be possible to write a custom app that would query the NASA raw images API and displays them fullscreen on the frame. The only problem was that I had never written an Android app before, but there&amp;rsquo;s a first time for everything. Once I reverse engineered the API used by the NASA raw image library webpage, and learned a little bit of Android development, the actual implementation of the app turned out to be fairly simple. While I don&amp;rsquo;t recommend anyone use my code for as any kind of reference, I have published all the code on my Gitlab project here: &lt;a href=&#34;https://gitlab.com/prbs23/mars-photo-stream&#34;&gt;Mars Photo Stream&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;

&lt;div class=&#34;box floatright&#34; style=&#34;max-width:50%&#34;&gt;
  &lt;figure class=&#34;floatright&#34; itemprop=&#34;associatedMedia&#34; itemscope itemtype=&#34;http://schema.org/ImageObject&#34;&gt;
    &lt;div class=&#34;img&#34;&gt;
      &lt;img itemprop=&#34;thumbnail&#34; src=&#34;https://prbs23.com/blog/blog/posts/picture-frame-from-mars/photo_frame_w_overlay.jpg&#34; alt=&#34;My custom Mars Photo Stream app running on the picture frame, displaying information overlay.&#34;/&gt;
      &lt;a href=&#34;https://prbs23.com/blog/blog/posts/picture-frame-from-mars/photo_frame_w_overlay.jpg&#34; itemprop=&#34;contentUrl&#34;&gt;&lt;/a&gt;
    &lt;/div&gt;
      &lt;figcaption&gt;
          &lt;p&gt;
            My custom Mars Photo Stream app running on the picture frame, displaying information overlay.
            
          &lt;/p&gt;
      &lt;/figcaption&gt;
  &lt;/figure&gt;
&lt;/div&gt;

The app mainly consists of two periodic looper handlers. One handler is responsible for updating a list of the latest 300 images by querying the NASA API every hour. The other handler is responsible for updating the image being displayed. It randomly selects one image from the list of latest images, downloads it, and then updates an ImageSwitcher widget with the new image. Other than these periodic handlers, I just needed a few buttons to handle pausing the automatic image advancement, skipping to a new image, and managing settings..&lt;/p&gt;
&lt;p&gt;Overall the app is functionally at a point where everything working well enough that I am happy to just have it on the wall. It&amp;rsquo;s stable, does what I set out to accomplish, and has enough configurability for daily use. Of course there are still some issues and areas for potential future improvements that I may pick up at a later time.&lt;/p&gt;
&lt;h2 id=&#34;next-steps&#34;&gt;Next Steps&lt;/h2&gt;
&lt;p&gt;The main issue with the picture frame is that somehow Frameo configuration the custom Android ROM to completely disable the soft navigation buttons (most importantly the back button). This is not a problem when operating inside my app, but when navigating the Android settings UI, this can be problematic. To close the Android settings app and get back to the picture frame app I currently need to &amp;ldquo;force stop&amp;rdquo; the settings app&amp;hellip; not exactly convenient. I have tried many suggestions on how to re-enable the navigation bar, but so far nothing I have tried worked. If anyone is experienced with the configuration of the Android SystemUI package and has ideas on how to re-enable it, &lt;a href=&#34;mailto:prbs23@prbs23.com&#34;&gt;get in touch&lt;/a&gt; because this really the only major issue I have.&lt;/p&gt;
&lt;p&gt;There are also two features new features that I would like to implement, but haven&amp;rsquo;t gotten around to yet. While I find most of the raw images have something interesting about them, occasionally the app will select an image that is just &amp;ldquo;static&amp;rdquo;, or a featureless sky, or something equally uninteresting. I would like to be able to have my app somehow automatically filter these images out before showing them. It seems possible that some kind of simple contrast analysis of the images should be able to identify these &amp;ldquo;uninteresting&amp;rdquo; images. Maybe I will tackle this problem when I want to start learning about image processing.&lt;/p&gt;
&lt;p&gt;Conversely, there will also sometimes be a really interesting image shows up that I would like to be able to save for later. My initial idea was to add a button which would send an email containing a link to the current image to a pre-configured address. Unfortunately, I wasn&amp;rsquo;t able to find any simple APIs for sending an email in the background, so I haven&amp;rsquo;t bothered to figure this out yet. I would still like to have the feature, but I&amp;rsquo;m no longer sure that email is the correct tool, maybe there&amp;rsquo;s a better alternative.&lt;/p&gt;
&lt;h2 id=&#34;making-your-own&#34;&gt;Making Your Own&lt;/h2&gt;
&lt;p&gt;Now I know what everyone is saying, how do I make one of these for myself? Overall this project turned out to be a lot less complicated than I initially expected, and should be easy to reproduce. The following steps should be all it takes:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Get yourself a Wi-Fi digital picture frame. If you want to play it safe you can get the same &lt;a href=&#34;https://www.amazon.com/dp/B083SH697H&#34;&gt;AKImart 10.1 Inch Smart WiFi Digital Photo Frame&lt;/a&gt; that I used. I would expect that at least pretty much any Frameo Wi-Fi digital picture frame would also work, but I don&amp;rsquo;t know that they will all be unlocked in the same way the AKImart one was.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Either build or download the APK for my &amp;ldquo;Mars Photo Stream&amp;rdquo; app. The &lt;a href=&#34;https://gitlab.com/prbs23/mars-photo-stream/-/releases&#34;&gt;Releases&lt;/a&gt; should always have an APK for the latest release of the app.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Install the Mars Photo Stream APK onto the picture frame using the ADB tool using the following command:
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ adb install com.prbs23.marsphotostream-v0.1.0.apk&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;If you don&amp;rsquo;t want to ever use the picture frame using the intended Frameo application, then you can disable it. If you don&amp;rsquo;t disable the Frameo &amp;ldquo;frame&amp;rdquo; app, then every time the picture frame boots up it will ask if you want to launch the Frameo app or Mars Photo Stream. Depending on your use case you may or may not want this.&lt;br&gt;
If you want to disable the Frameo app so it always boots into the Mars Photo Stream app, then run the following commands at the ADB shell:
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ adb shell
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;shell@ZN-DP1007$ su root
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;root@ZN-DP1007$ pm disable net.frameo.frame
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;root@ZN-DP1007$ pm hide net.frameo.frame&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Configure the Wi-Fi setting for the picture frame so that it can access the internet.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If everything has goes as expected, the Mars Photo Stream app should now be running on your picture frame, and will automatically start displaying raw images from the Perseverance rover and Ingenuity helicopter.&lt;/p&gt;
&lt;p&gt;In theory the Mars Photo Stream app could also be installed onto any Android phone or tablet and used as a picture frame, though I haven&amp;rsquo;t tested this. In this case you can directly download the &lt;a href=&#34;https://gitlab.com/prbs23/mars-photo-stream/-/releases&#34;&gt;latest APK file&lt;/a&gt; onto the device and install it. If there is enough interest I could likely get the app on the Google Play Store, but for a personal project I didn&amp;rsquo;t bother figuring out how to do this.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Bidirectional Delay in SystemVerilog</title>
      <link>https://prbs23.com/blog/posts/bidirectional-delay-in-systemverilog/</link>
      <pubDate>Fri, 22 Oct 2021 07:07:39 -0600</pubDate>
      <author>prbs23@prbs23.com (prbs23)</author>
      <guid>https://prbs23.com/blog/posts/bidirectional-delay-in-systemverilog/</guid>
      <description>&lt;p&gt;I recently wrote about &lt;a href=&#34;https://prbs23.com/blog/posts/drive-strength-detection-in-system-verilog/&#34;&gt;detecting driver strength in SystemVerilog&lt;/a&gt;. That work actually came out of solving a larger problem: How do you build a bidirectional digital wire model that includes propagation delay?&lt;/p&gt;
&lt;h2 id=&#34;motivation&#34;&gt;Motivation&lt;/h2&gt;
&lt;p&gt;The problem I had was how to model, in a digital simulation, the behavior of a &amp;ldquo;channel&amp;rdquo; (wire) for a high speed SerDes link. At the symbol rates used for modern high speed SerDes links, we start running into the physical limitations of copper as a conductor: the attenuation, frequency response, and speed of signals propagating through the channel are all factors that cannot be ignored as they might usually be. An additional requirement that my channel model had, was that it needed to be bidirectional. For my gate models to function, I not only needed to model the propagation delay of signals through the channel, but I needed drive strength resolution to resolve the value of the channel with drivers on both ends.&lt;/p&gt;
&lt;p&gt;The protocol for the PHY I was modeling specifies that the transmitter should only be enabled when it detects that there is a receiver connected to it. The way this detection is done is by having the transmitter sense the presence of the termination resistor in the receiver. This is convenient because it lets the transmitter do endpoint detection without any extra wires, but it does complicate the channel modeling, because a lot of SystemVerilog constructs do not resolve drive strengths in both directions.&lt;/p&gt;


&lt;div class=&#34;box &#34; &gt;
  &lt;figure  itemprop=&#34;associatedMedia&#34; itemscope itemtype=&#34;http://schema.org/ImageObject&#34;&gt;
    &lt;div class=&#34;img&#34;&gt;
      &lt;img itemprop=&#34;thumbnail&#34; src=&#34;https://prbs23.com/blog/blog/posts/bidirectional-delay-in-systemverilog/serdes_with_endpoint_detection.svg&#34; alt=&#34;Basic schematic diagram of system.&#34;/&gt;
      &lt;a href=&#34;https://prbs23.com/blog/blog/posts/bidirectional-delay-in-systemverilog/serdes_with_endpoint_detection.svg&#34; itemprop=&#34;contentUrl&#34;&gt;&lt;/a&gt;
    &lt;/div&gt;
      &lt;figcaption&gt;
          &lt;p&gt;
            Basic schematic diagram of system.
            
          &lt;/p&gt;
      &lt;/figcaption&gt;
  &lt;/figure&gt;
&lt;/div&gt;

&lt;h2 id=&#34;a-first-attempt&#34;&gt;A First Attempt&lt;/h2&gt;
&lt;p&gt;While constructing a model that could inject bit flip errors and remain bidirectional was a little tricky, its not too difficult with the right set up of &lt;code&gt;tranif&lt;/code&gt; gates. What turned out to be the tricky part was modeling propagation delay, because as far as I could find, all SystemVerilog constructs which introduced a delay, also behave as unidirectional drivers. So, how can I make a module where a driver change on either port will appear, after a delay, on the other?&lt;/p&gt;
&lt;h3 id=&#34;breaking-down-the-problem&#34;&gt;Breaking Down The Problem&lt;/h3&gt;
&lt;p&gt;An important thing to remember is that in SystemVerilog a net value is really a combination of two components, a value (&lt;code&gt;0&lt;/code&gt;, &lt;code&gt;1&lt;/code&gt;, &lt;code&gt;z&lt;/code&gt;, or &lt;code&gt;x&lt;/code&gt;), and a strength (&lt;code&gt;highz&lt;/code&gt;, &lt;code&gt;weak&lt;/code&gt;, &lt;code&gt;pull&lt;/code&gt;, &lt;code&gt;strong&lt;/code&gt;, or &lt;code&gt;supply&lt;/code&gt;). It&amp;rsquo;s easy to to delay the value part, but in SystemVerilog this always loses the strength part. Considering this, I hypothesized that if I could decompose the net value into two separate signals (value and strength), then recompose them on the other side of the delay, I could make a strength preserving delay module. If that works, then I could put two of those circuits back to back to make a truly bidirectional delay module.&lt;/p&gt;
&lt;p&gt;The basic idea was to first build a strength maintaining delay element. To do this I needed three pieces: To decompose the net value I needed a strength detector which would take in a net, a output a value proportional to the strength of the net&amp;rsquo;s driver. To recompose the net value I needed a variable strength driver which would take in two &amp;ldquo;values&amp;rdquo; a net value and a net strength, and would drive an output net with the specified strength and value. Finally I would need a controllable delay element so that the delay could be controlled by my testbench. Once I had the unidirectional delay, I could put two of these back to back, as shown in the system schematic below, to create the bidirectional delay I needed.&lt;/p&gt;


&lt;div class=&#34;box &#34; &gt;
  &lt;figure  itemprop=&#34;associatedMedia&#34; itemscope itemtype=&#34;http://schema.org/ImageObject&#34;&gt;
    &lt;div class=&#34;img&#34;&gt;
      &lt;img itemprop=&#34;thumbnail&#34; src=&#34;https://prbs23.com/blog/blog/posts/bidirectional-delay-in-systemverilog/bidir_delay_element_schem_initial.png&#34; alt=&#34;Schematic showing structure of first bidirectional delay module concept.&#34;/&gt;
      &lt;a href=&#34;https://prbs23.com/blog/blog/posts/bidirectional-delay-in-systemverilog/bidir_delay_element_schem_initial.png&#34; itemprop=&#34;contentUrl&#34;&gt;&lt;/a&gt;
    &lt;/div&gt;
      &lt;figcaption&gt;
          &lt;p&gt;
            Schematic showing structure of first bidirectional delay module concept.
            
          &lt;/p&gt;
      &lt;/figcaption&gt;
  &lt;/figure&gt;
&lt;/div&gt;

&lt;p&gt;First, I needed a way to convert the strength of a driver on a net to a SystemVerilog value. This turned out to be a deep hole all on it&amp;rsquo;s own, and I&amp;rsquo;ve already written about it at length &lt;a href=&#34;https://prbs23.com/blog/posts/drive-strength-detection-in-system-verilog/&#34;&gt;in my last blog post&lt;/a&gt;. There are a couple ways of doing this doing this with different trade-offs, but for the purposes of this model I used the Verilog only &amp;ldquo;sense net&amp;rdquo; strength detection method because it&amp;rsquo;s a nice fast standalone implementation. It detects &lt;code&gt;supply&lt;/code&gt; strength drivers as &lt;code&gt;strong&lt;/code&gt; but that was okay for my use case. The code for that is shown below, for details on how it works, that can be found in my previous post.&lt;/p&gt;
&lt;figure class=&#34;no-photoswipe&#34;&gt;
  &lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 1
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 2
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 3
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 4
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 5
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 6
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 7
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 8
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 9
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;10
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;11
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;12
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;13
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;14
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;15
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;16
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;17
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;18
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;19
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;20
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;21
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;22
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;23
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;24
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;25
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;26
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;27
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;28
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-systemverilog&#34; data-lang=&#34;systemverilog&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;module&lt;/span&gt; sense_net_strength_detect (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;inout&lt;/span&gt; sig,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;output&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;reg&lt;/span&gt; [&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;] strength
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;wire&lt;/span&gt; strong_sense;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;wire&lt;/span&gt; pull_sense;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;wire&lt;/span&gt; weak_sense;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;assign&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;strong1&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;strong0&lt;/span&gt;) strong_sense &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; (sig &lt;span style=&#34;color:#f92672&#34;&gt;===&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&amp;#39;bx) &lt;span style=&#34;color:#f92672&#34;&gt;?&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;~&lt;/span&gt;sig;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;assign&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;pull1&lt;/span&gt;  , &lt;span style=&#34;color:#66d9ef&#34;&gt;pull0&lt;/span&gt;  ) pull_sense   &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; (sig &lt;span style=&#34;color:#f92672&#34;&gt;===&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&amp;#39;bx) &lt;span style=&#34;color:#f92672&#34;&gt;?&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;~&lt;/span&gt;sig;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;assign&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;weak1&lt;/span&gt;  , &lt;span style=&#34;color:#66d9ef&#34;&gt;weak0&lt;/span&gt;  ) weak_sense   &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; (sig &lt;span style=&#34;color:#f92672&#34;&gt;===&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&amp;#39;bx) &lt;span style=&#34;color:#f92672&#34;&gt;?&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;~&lt;/span&gt;sig;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;cmos&lt;/span&gt; strong_gate(strong_sense, sig, &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;cmos&lt;/span&gt; pull_gate  (pull_sense  , sig, &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;cmos&lt;/span&gt; weak_gate  (weak_sense  , sig, &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;assign&lt;/span&gt; strength &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (sig &lt;span style=&#34;color:#f92672&#34;&gt;===&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&amp;#39;bz) &lt;span style=&#34;color:#f92672&#34;&gt;?&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (sig &lt;span style=&#34;color:#f92672&#34;&gt;===&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&amp;#39;bx) &lt;span style=&#34;color:#f92672&#34;&gt;?&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (pull_sense   &lt;span style=&#34;color:#f92672&#34;&gt;!==&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&amp;#39;bx) &lt;span style=&#34;color:#f92672&#34;&gt;?&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (strong_sense &lt;span style=&#34;color:#f92672&#34;&gt;!==&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&amp;#39;bx) &lt;span style=&#34;color:#f92672&#34;&gt;?&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ) &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (weak_sense   &lt;span style=&#34;color:#f92672&#34;&gt;===&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&amp;#39;bx) &lt;span style=&#34;color:#f92672&#34;&gt;?&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (pull_sense   &lt;span style=&#34;color:#f92672&#34;&gt;===&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&amp;#39;bx) &lt;span style=&#34;color:#f92672&#34;&gt;?&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    )
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  );
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;endmodule&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
  
    &lt;figcaption&gt;&lt;span&gt;sense_net_strength_detect.sv&lt;/span&gt;&lt;/figcaption&gt;
  
&lt;/figure&gt;

&lt;p&gt;The next piece I needed was a module that has &amp;ldquo;value&amp;rdquo; and &amp;ldquo;strength&amp;rdquo; inputs, and will drive an output node high or low with the given strength level. There turns out to be a few ways to do this, but the cleanest approach I found was to use two assign statements for each strength level: One which can only drive a &lt;code&gt;&#39;1&lt;/code&gt; value with the given strength, and one which can only drive a &lt;code&gt;&#39;0&lt;/code&gt; value with the given strength. Then the value of the assign statement is the &amp;ldquo;value&amp;rdquo; input ORed or ANDed with a strength value comparison so that only the correct assign statement is active for the given value of the &amp;ldquo;strength&amp;rdquo; input. The code for this module looks like the following:&lt;/p&gt;
&lt;figure class=&#34;no-photoswipe&#34;&gt;
  &lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 1
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 2
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 3
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 4
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 5
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 6
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 7
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 8
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 9
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;10
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;11
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;12
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;13
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;14
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-systemverilog&#34; data-lang=&#34;systemverilog&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;module&lt;/span&gt; multi_strength_driver (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;input&lt;/span&gt;       value,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;input&lt;/span&gt; [&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;] strength, &lt;span style=&#34;color:#75715e&#34;&gt;// highz = 0, weak = 1, pull = 2, strong = 3, supply = 4
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;inout&lt;/span&gt; sig
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;assign&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;supply0&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;highz1&lt;/span&gt; ) sig &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; value &lt;span style=&#34;color:#f92672&#34;&gt;||&lt;/span&gt; (strength &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;assign&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;highz0&lt;/span&gt;,  &lt;span style=&#34;color:#66d9ef&#34;&gt;supply1&lt;/span&gt;) sig &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; value &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; (strength &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;assign&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;strong0&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;highz1&lt;/span&gt; ) sig &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; value &lt;span style=&#34;color:#f92672&#34;&gt;||&lt;/span&gt; (strength &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;assign&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;highz0&lt;/span&gt;,  &lt;span style=&#34;color:#66d9ef&#34;&gt;strong1&lt;/span&gt;) sig &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; value &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; (strength &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;assign&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;pull0&lt;/span&gt;,   &lt;span style=&#34;color:#66d9ef&#34;&gt;highz1&lt;/span&gt; ) sig &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; value &lt;span style=&#34;color:#f92672&#34;&gt;||&lt;/span&gt; (strength &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;assign&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;highz0&lt;/span&gt;,  &lt;span style=&#34;color:#66d9ef&#34;&gt;pull1&lt;/span&gt;  ) sig &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; value &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; (strength &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;assign&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;weak0&lt;/span&gt;,   &lt;span style=&#34;color:#66d9ef&#34;&gt;highz1&lt;/span&gt; ) sig &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; value &lt;span style=&#34;color:#f92672&#34;&gt;||&lt;/span&gt; (strength &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;assign&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;highz0&lt;/span&gt;,  &lt;span style=&#34;color:#66d9ef&#34;&gt;weak1&lt;/span&gt;  ) sig &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; value &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; (strength &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;endmodule&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
  
    &lt;figcaption&gt;&lt;span&gt;multi_strength_driver.sv&lt;/span&gt;&lt;/figcaption&gt;
  
&lt;/figure&gt;

&lt;p&gt;Finally, the programmable delays could be simple assign statements with a delay value. Since I&amp;rsquo;m breaking up the strength and value of the signal, and providing independent data paths in each direction, there is no need to try to preserve drive strength in these assignments or use bidirectional gates.&lt;/p&gt;
&lt;h3 id=&#34;putting-it-all-together-for-the-first-time&#34;&gt;Putting It All Together &lt;em&gt;(For The First Time)&lt;/em&gt;&lt;/h3&gt;
&lt;p&gt;Now that I had all the pieces, I just needed to stick them together and try it out. For each of the two &lt;code&gt;inout&lt;/code&gt;, I created a &amp;ldquo;sense_strength&amp;rdquo; signal that was the value representation of that net&amp;rsquo;s drive strength, and two &lt;code&gt;reg&lt;/code&gt; signals to hold the delayed value and strength values for the multi_strength_driver, from the other side of the link.&lt;/p&gt;
&lt;figure class=&#34;no-photoswipe&#34;&gt;
  &lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 1
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 2
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 3
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 4
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 5
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 6
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 7
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 8
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 9
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;10
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;11
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;12
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;13
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;14
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;15
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;16
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;17
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;18
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;19
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;20
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;21
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;22
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;23
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;24
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;25
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;26
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;27
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;28
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;29
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;30
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;31
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-systemverilog&#34; data-lang=&#34;systemverilog&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;module&lt;/span&gt; bidir_delay_initial #(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;parameter&lt;/span&gt; DELAY_WIDTH&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;32&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;) (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;inout&lt;/span&gt; sig_a,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;inout&lt;/span&gt; sig_b,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;input&lt;/span&gt; [DELAY_WIDTH&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;] delay
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;wire&lt;/span&gt; [&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;] sense_strength_a;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;reg&lt;/span&gt;        drive_value_a;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;reg&lt;/span&gt;  [&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;] drive_strength_a;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;wire&lt;/span&gt; [&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;] sense_strength_b;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;reg&lt;/span&gt;        drive_value_b;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;reg&lt;/span&gt;  [&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;] drive_strength_b;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  sense_net_strength_detect sense_a(.sig(sig_a), .strength(sense_strength_a));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  sense_net_strength_detect sense_b(.sig(sig_b), .strength(sense_strength_b));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  multi_strength_driver drive_a(.sig(sig_a), .strength(drive_strength_a), .value(drive_value_a));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  multi_strength_driver drive_b(.sig(sig_b), .strength(drive_strength_b), .value(drive_value_b));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;initial&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;begin&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    drive_value_a    &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&amp;#39;d0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    drive_strength_a &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&amp;#39;d0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    drive_value_b    &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&amp;#39;b0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    drive_strength_b &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&amp;#39;d0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;always&lt;/span&gt; @(sig_b)            drive_value_a    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;=&lt;/span&gt; #(delay) sig_b;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;always&lt;/span&gt; @(sense_strength_b) drive_strength_a &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;=&lt;/span&gt; #(delay) sense_strength_b;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;always&lt;/span&gt; @(sig_a)            drive_value_b    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;=&lt;/span&gt; #(delay) sig_a;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;always&lt;/span&gt; @(sense_strength_a) drive_strength_b &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;=&lt;/span&gt; #(delay) sense_strength_a;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;endmodule&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
  
    &lt;figcaption&gt;&lt;span&gt;bidir_delay_initial.sv&lt;/span&gt;&lt;/figcaption&gt;
  
&lt;/figure&gt;

&lt;p&gt;To test my solution I created a basic little testbench. On one side (side A) of my delay module I put another instance of my multi-strength driver module, so I could dynamically control the strength of the driver on that side, and to the other (side B), I placed &lt;code&gt;weak&lt;/code&gt; strength driver to 0&lt;/p&gt;


&lt;div class=&#34;box &#34; &gt;
  &lt;figure  itemprop=&#34;associatedMedia&#34; itemscope itemtype=&#34;http://schema.org/ImageObject&#34;&gt;
    &lt;div class=&#34;img&#34;&gt;
      &lt;img itemprop=&#34;thumbnail&#34; src=&#34;https://prbs23.com/blog/blog/posts/bidirectional-delay-in-systemverilog/bidir_delay_tb.png&#34; alt=&#34;Simple bidirectional delay test bench.&#34;/&gt;
      &lt;a href=&#34;https://prbs23.com/blog/blog/posts/bidirectional-delay-in-systemverilog/bidir_delay_tb.png&#34; itemprop=&#34;contentUrl&#34;&gt;&lt;/a&gt;
    &lt;/div&gt;
      &lt;figcaption&gt;
          &lt;p&gt;
            Simple bidirectional delay test bench.
            
          &lt;/p&gt;
      &lt;/figcaption&gt;
  &lt;/figure&gt;
&lt;/div&gt;

&lt;p&gt;For initial turn on I used a sequence that would start by driving a &lt;code&gt;strong1&lt;/code&gt;, decreasing strength down to &lt;code&gt;highz&lt;/code&gt;, and then increase the strength back to &lt;code&gt;strong&lt;/code&gt; with a value of 0 on the net &lt;code&gt;a&lt;/code&gt;. Between each step I used a 10ns delay, and the delay element was set with a fixed 2ns delay.&lt;/p&gt;
&lt;p&gt;Unfortunately, my initial results were not what I was intending, I expected that the &lt;code&gt;b&lt;/code&gt; net would be initially high, transition to &lt;code&gt;1&#39;bx&lt;/code&gt; 2ns after the &lt;code&gt;a&lt;/code&gt; driver changes strength to &lt;code&gt;weak1&lt;/code&gt;, and then transition low 2ns after the &lt;code&gt;a&lt;/code&gt; driver transitioned to &lt;code&gt;highz&lt;/code&gt;. The &lt;code&gt;a&lt;/code&gt; net should have been high until 4ns after the &lt;code&gt;a&lt;/code&gt; driver strength goes to 1, when it should to go to a &lt;code&gt;1&#39;bx&lt;/code&gt;. After the &lt;code&gt;a&lt;/code&gt; driver goes to a strength of zero it should be pulled low by the pulldown on net &lt;code&gt;b&lt;/code&gt;. What the simulation results, as seen below, actually showed was both nets &lt;code&gt;a&lt;/code&gt; and &lt;code&gt;b&lt;/code&gt; being driven high (with a &lt;code&gt;strong&lt;/code&gt; driver) until the driver on side &lt;code&gt;a&lt;/code&gt; drove a &lt;code&gt;strong0&lt;/code&gt;, when both sides go to &lt;code&gt;strongX&lt;/code&gt;.&lt;/p&gt;


&lt;div class=&#34;box &#34; &gt;
  &lt;figure  itemprop=&#34;associatedMedia&#34; itemscope itemtype=&#34;http://schema.org/ImageObject&#34;&gt;
    &lt;div class=&#34;img&#34;&gt;
      &lt;img itemprop=&#34;thumbnail&#34; src=&#34;https://prbs23.com/blog/blog/posts/bidirectional-delay-in-systemverilog/bidir_delay_latchup.png&#34; alt=&#34;Simulation waveforms from initial bidirectional delay module showing positive feedback latch behavior.&#34;/&gt;
      &lt;a href=&#34;https://prbs23.com/blog/blog/posts/bidirectional-delay-in-systemverilog/bidir_delay_latchup.png&#34; itemprop=&#34;contentUrl&#34;&gt;&lt;/a&gt;
    &lt;/div&gt;
      &lt;figcaption&gt;
          &lt;p&gt;
            Simulation waveforms from initial bidirectional delay module showing positive feedback latch behavior.
            
          &lt;/p&gt;
      &lt;/figcaption&gt;
  &lt;/figure&gt;
&lt;/div&gt;

&lt;p&gt;While not the intended result, an astute observer may have predicted this behavior simply from looking at the initial simplified schematic. By putting two of the same strength preserving delays back to back, I created a positive feedback loop in the net strength. After 2x the delay duration from time 0, the variable strength driver inside the delay module wll be driving the same value and strength as the strongest external driver on either side of the delay. If the external driver changes value or strength the internal driver will continue to drive the old value for 2x the delay duration. Unless the net is externally driven with a larger strength than it was before, the net will continue to hold the old value. This is somewhat akin to the latching behavior you get from a unity gain amplifier with positive feedback.&lt;/p&gt;
&lt;h2 id=&#34;breaking-the-feedback-loop-a-more-correct-delay&#34;&gt;Breaking the Feedback Loop &lt;em&gt;(a more correct delay)&lt;/em&gt;&lt;/h2&gt;
&lt;p&gt;To actually make this delay element to behave correctly, I needed to break the positive feedback loop caused when one of the variable-strength drivers in the delay element is the strongest driver on it&amp;rsquo;s net. I found that this is possible by only enabling the driver on port &lt;code&gt;b&lt;/code&gt; when the driver on port &lt;code&gt;a&lt;/code&gt; is not driving the net, and vice versa. While there isn&amp;rsquo;t a (native) way to know which driver is driving a net, a close enough approximation is if the detected value and strength of the net matches the value and strength inputs to the variable-strength driver on that net. If the strength and value match, then the driver on the opposite port is disabled, which breaks the feedback loop.&lt;/p&gt;


&lt;div class=&#34;box &#34; &gt;
  &lt;figure  itemprop=&#34;associatedMedia&#34; itemscope itemtype=&#34;http://schema.org/ImageObject&#34;&gt;
    &lt;div class=&#34;img&#34;&gt;
      &lt;img itemprop=&#34;thumbnail&#34; src=&#34;https://prbs23.com/blog/blog/posts/bidirectional-delay-in-systemverilog/bidir_delay_element_schem.png&#34; alt=&#34;Schematic showing structure of bidirectional delay module with broken feedback loop.&#34;/&gt;
      &lt;a href=&#34;https://prbs23.com/blog/blog/posts/bidirectional-delay-in-systemverilog/bidir_delay_element_schem.png&#34; itemprop=&#34;contentUrl&#34;&gt;&lt;/a&gt;
    &lt;/div&gt;
      &lt;figcaption&gt;
          &lt;p&gt;
            Schematic showing structure of bidirectional delay module with broken feedback loop.
            
          &lt;/p&gt;
      &lt;/figcaption&gt;
  &lt;/figure&gt;
&lt;/div&gt;

&lt;p&gt;While this is actually a conceptually simple way to break up the feedback loop, the trick turned out to be expressing it in SystemVerilog such that it wouldn&amp;rsquo;t cause zero-time loops in the simulator when resolving the bidirectional net values. After a decent amount of experimentation, the solution turned out to be correct partitioning of &lt;code&gt;always&lt;/code&gt; blocks and some well placed &lt;code&gt;#0&lt;/code&gt; delays to force net resolution order. Note that there has to be some additional special handling for &lt;code&gt;1&#39;bx&lt;/code&gt; values, because they can be the result of multiple drivers on one net. The code for my final bidirectional delay module is shown below.&lt;/p&gt;
&lt;figure class=&#34;no-photoswipe&#34;&gt;
  &lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 1
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 2
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 3
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 4
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 5
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 6
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 7
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 8
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 9
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;10
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;11
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;12
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;13
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;14
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;15
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;16
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;17
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;18
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;19
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;20
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;21
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;22
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;23
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;24
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;25
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;26
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;27
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;28
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;29
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;30
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;31
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;32
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;33
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;34
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;35
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;36
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;37
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;38
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;39
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;40
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;41
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;42
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;43
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;44
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;45
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-systemverilog&#34; data-lang=&#34;systemverilog&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;module&lt;/span&gt; bidir_delay #(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;parameter&lt;/span&gt; DELAY_WIDTH&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;32&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;) (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;inout&lt;/span&gt; sig_a,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;inout&lt;/span&gt; sig_b,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;input&lt;/span&gt; [DELAY_WIDTH&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;] delay
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;wire&lt;/span&gt; [&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;] sense_strength_a, sense_strength_b;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;reg&lt;/span&gt;  [&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;] drive_strength_a, drive_strength_b;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;reg&lt;/span&gt;        sense_value_a, sense_value_a;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;reg&lt;/span&gt;        drive_value_a, drive_value_a;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;reg&lt;/span&gt;        driving_a, driving_b;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  sense_net_strength_detect sense_a(.sig(sig_a), .strength(sense_strength_a));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  sense_net_strength_detect sense_b(.sig(sig_b), .strength(sense_strength_b));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  multi_strength_driver drive_a(.sig(sig_a), .strength(drive_strength_a), .value(drive_value_a));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  multi_strength_driver drive_b(.sig(sig_b), .strength(drive_strength_b), .value(drive_value_b));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;initial&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;begin&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    drive_value_a    &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&amp;#39;d0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    drive_strength_a &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&amp;#39;d0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    drive_value_b    &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&amp;#39;b0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    drive_strength_b &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&amp;#39;d0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    driving_a        &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&amp;#39;d0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    driving_b        &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&amp;#39;d0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;always&lt;/span&gt; @(driving_a, sig_a) &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#f92672&#34;&gt;!&lt;/span&gt;driving_a) drive_value_a_delay &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;=&lt;/span&gt; #(delay) sig_a;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;always&lt;/span&gt; @(driving_b, sig_b) &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#f92672&#34;&gt;!&lt;/span&gt;driving_b) drive_value_a_delay &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;=&lt;/span&gt; #(delay) sig_b;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;always&lt;/span&gt; @(sense_value_a_delay) drive_value_b &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;=&lt;/span&gt; (sense_value_a_delay &lt;span style=&#34;color:#f92672&#34;&gt;===&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&amp;#39;bx) &lt;span style=&#34;color:#f92672&#34;&gt;?&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;~&lt;/span&gt;sig_b &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; sense_value_a_delay;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;always&lt;/span&gt; @(sense_value_b_delay) drive_value_a &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;=&lt;/span&gt; (sense_value_b_delay &lt;span style=&#34;color:#f92672&#34;&gt;===&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&amp;#39;bx) &lt;span style=&#34;color:#f92672&#34;&gt;?&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;~&lt;/span&gt;sig_a &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; sense_value_b_delay;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;always&lt;/span&gt; @(driving_a, sense_strength_a) &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#f92672&#34;&gt;!&lt;/span&gt;driving_a) drive_strength_b &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;=&lt;/span&gt; #(delay) sense_strength_a;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;always&lt;/span&gt; @(driving_b, sense_strength_b) &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#f92672&#34;&gt;!&lt;/span&gt;driving_b) drive_strength_a &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;=&lt;/span&gt; #(delay) sense_strength_b;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;always&lt;/span&gt; @(&lt;span style=&#34;color:#66d9ef&#34;&gt;posedge&lt;/span&gt; driving_a) drive_strength_b &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;=&lt;/span&gt; #(delay) &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&amp;#39;b0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;always&lt;/span&gt; @(&lt;span style=&#34;color:#66d9ef&#34;&gt;posedge&lt;/span&gt; driving_b) drive_strength_a &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;=&lt;/span&gt; #(delay) &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&amp;#39;b0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;always&lt;/span&gt; @(sig_a, drive_value_a, drive_strength_a, sense_strength_a) &lt;span style=&#34;color:#66d9ef&#34;&gt;begin&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    #&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;; &lt;span style=&#34;color:#75715e&#34;&gt;// Evaluate this after all the inputs have settled to prevent extra delta cycles.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    driving_a &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;=&lt;/span&gt; (sig_a &lt;span style=&#34;color:#f92672&#34;&gt;===&lt;/span&gt; drive_value_a) &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; (drive_value_a &lt;span style=&#34;color:#f92672&#34;&gt;!==&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&amp;#39;bx) &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; (sense_strength_a &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; drive_strength_a);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;always&lt;/span&gt; @(sig_b, drive_value_b, drive_strength_b, sense_strength_b) &lt;span style=&#34;color:#66d9ef&#34;&gt;begin&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    #&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;; &lt;span style=&#34;color:#75715e&#34;&gt;// Evaluate this after all the inputs have settled to prevent extra delta cycles.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    driving_b &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;=&lt;/span&gt; (sig_b &lt;span style=&#34;color:#f92672&#34;&gt;===&lt;/span&gt; drive_value_b) &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; (drive_value_b &lt;span style=&#34;color:#f92672&#34;&gt;!==&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&amp;#39;bx) &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; (sense_strength_b &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; drive_strength_b);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;endmodule&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
  
    &lt;figcaption&gt;&lt;span&gt;bidir_delay.sv&lt;/span&gt;&lt;/figcaption&gt;
  
&lt;/figure&gt;

&lt;p&gt;Using the same testbench as before, simulating this modified delay module resulted in the waves shown below. With the positive feedback loop broken, we now get the expected behavior on the bidriectional nets. The &lt;code&gt;a&lt;/code&gt; node gets pulled down by the pulldown on net &lt;code&gt;b&lt;/code&gt;after the 2x delay period, instead of latching the &lt;code&gt;strong&lt;/code&gt; value, as the old implementation did.&lt;/p&gt;


&lt;div class=&#34;box &#34; &gt;
  &lt;figure  itemprop=&#34;associatedMedia&#34; itemscope itemtype=&#34;http://schema.org/ImageObject&#34;&gt;
    &lt;div class=&#34;img&#34;&gt;
      &lt;img itemprop=&#34;thumbnail&#34; src=&#34;https://prbs23.com/blog/blog/posts/bidirectional-delay-in-systemverilog/bidir_delay_waves.png&#34; alt=&#34;Simulation results of bidirectional delay module showing expected behavior, after breaking feedback loop.&#34;/&gt;
      &lt;a href=&#34;https://prbs23.com/blog/blog/posts/bidirectional-delay-in-systemverilog/bidir_delay_waves.png&#34; itemprop=&#34;contentUrl&#34;&gt;&lt;/a&gt;
    &lt;/div&gt;
      &lt;figcaption&gt;
          &lt;p&gt;
            Simulation results of bidirectional delay module showing expected behavior, after breaking feedback loop.
            
          &lt;/p&gt;
      &lt;/figcaption&gt;
  &lt;/figure&gt;
&lt;/div&gt;

&lt;h3 id=&#34;remaining-issues&#34;&gt;Remaining Issues&lt;/h3&gt;
&lt;p&gt;The most significant remaining issue with this design is that if the &lt;code&gt;delay&lt;/code&gt; port is set to 0, it can cause an infinite zero-time loop in the simulator. For my use case, the I was able to externally ensure that the delay input never was set to 0, but if this was not possible, one could also add &lt;code&gt;tranif&lt;/code&gt; gates to disconnect and bypass the drivers when the delay input was set to zero. The other significant issue is that it cannot handle &lt;code&gt;supply&lt;/code&gt; strength net values, mainly because of the approach used to sense the net drive strength. If this was a significant issue, the DPI drive strength detection implementation from my previous blog post could be used in place of the sense-net one I used.&lt;/p&gt;
&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;While there are still some corner cases with this bidirectional delay implementation that don&amp;rsquo;t quite match with reality, it has proven to be fairly solid in production. The fact that it was possible to implement in pure SystemVerilog is both convenient, and means that it should be portable to any simulator. In the end, this project gave me the opportunity to really dig into the details of how net resolution, strength modeling, as well as gate primetives actually work in SystemVerilog.&lt;/p&gt;
&lt;p&gt;If you would like to play around with my bidirectional delay module, you can find an implementation on EDA Playgound here: &lt;a href=&#34;https://www.edaplayground.com/x/2PdE&#34;&gt;https://www.edaplayground.com/x/2PdE&lt;/a&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Drive Strength Detection in SystemVerilog</title>
      <link>https://prbs23.com/blog/posts/drive-strength-detection-in-system-verilog/</link>
      <pubDate>Tue, 21 Sep 2021 22:44:59 -0600</pubDate>
      <author>prbs23@prbs23.com (prbs23)</author>
      <guid>https://prbs23.com/blog/posts/drive-strength-detection-in-system-verilog/</guid>
      <description>&lt;p&gt;From time to time I will run across small problems or challenges in my day job which seem as though they should be simple enough but get stuck in my mind until they are fully investigated. This is one such issue I ran into a while ago: How can a verilog model determine the drive strength of a net value in SystemVerilog?&lt;/p&gt;
&lt;p&gt;When I initially ran into this problem, I thought it would require a quick search through the LRM and I&amp;rsquo;d be on my way. However, after some searching and not finding any useful constructs in the language that would directly provide visibility into a net&amp;rsquo;s drive strength, I ended up on google, and all the recommendations were similar to this post from stack overflow: &lt;a href=&#34;https://stackoverflow.com/questions/28402691/how-to-check-signal-drive-strength&#34;&gt;How to check signal drive strength?&lt;/a&gt;. It seemed the recommended solution was to format the net value using the &lt;code&gt;&amp;quot;%v&amp;quot;&lt;/code&gt; format string, and then do string comparisons on the formatted value.&lt;/p&gt;
&lt;p&gt;Having run into my fair share of string and string formatting performance issues in SystemVerilog in the past, the suggested &amp;ldquo;solution&amp;rdquo; was instantly ringing some alarm bells. This is the problem that latched into my mind, and I needed to know if there was a better way&amp;hellip; but first, a quick refresher on the drive strength modeling features in SystemVerilog.&lt;/p&gt;
&lt;h2 id=&#34;drive-strength-modeling&#34;&gt;Drive Strength Modeling&lt;/h2&gt;
&lt;p&gt;In SystemVerilog (and Verilog before it), a &amp;ldquo;net&amp;rdquo; is a special type of variable construct which is used to structurally model a wire in a circuit. The value of the &amp;ldquo;net&amp;rdquo; variable is a combination of a 4-state logical value (&lt;code&gt;0&lt;/code&gt;,&lt;code&gt;1&lt;/code&gt;,&lt;code&gt;z&lt;/code&gt;,&lt;code&gt;x&lt;/code&gt;), and a strength value (&lt;code&gt;highz&lt;/code&gt;, &lt;code&gt;weak&lt;/code&gt;, &lt;code&gt;pull&lt;/code&gt;, &lt;code&gt;strong&lt;/code&gt;, or &lt;code&gt;supply&lt;/code&gt;). The value of a net is determined by &amp;ldquo;driver&amp;rdquo; elements connected to the net, which can be either continuous assignment expressions, or gate level modeling primitives. If semantically a SystemVerilog net represents a wire in a circuit, and the logical value represents the &lt;em&gt;voltage&lt;/em&gt; on the wire, then the strength of the net represents how much &lt;em&gt;current&lt;/em&gt; can that wire can source (or said another way, the impedance of the driver).&lt;/p&gt;
&lt;p&gt;For every delta cycle of a simulation, the simulator will determine the logical and strength values of each net, by looking at the value and strength of all driver expressions on the net. If a net has no active drivers, then the value of the net is &amp;ldquo;high impedance&amp;rdquo; represented as &lt;code&gt;&#39;z&lt;/code&gt; in SystemVerilog 4-state values. If a net has one driver expression or primitive, then the value and strength of the net are equal to that of the driver. However, if there are more than one driver connected to a single net, the logical value of the net is determined by comparing the strength of each driver on the net. If there is one driver on the net that has a strength lager than the rest, or there are multiple drivers that all have the same largest strength value, and the same logical value, then the logical value of the net is determined by the logical value of the driver with the greatest strength. If there are multiple drivers that all have the same greatest strength on the net, but have different values, then the value of the net is &amp;ldquo;unknown&amp;rdquo; or &lt;code&gt;&#39;x&lt;/code&gt; with the strength of the strongest drivers.&lt;/p&gt;


&lt;div class=&#34;box &#34; &gt;
  &lt;figure  itemprop=&#34;associatedMedia&#34; itemscope itemtype=&#34;http://schema.org/ImageObject&#34;&gt;
    &lt;div class=&#34;img&#34;&gt;
      &lt;img itemprop=&#34;thumbnail&#34; src=&#34;https://prbs23.com/blog/blog/posts/drive-strength-detection-in-system-verilog/sv_drive_strengths.svg&#34; alt=&#34;Extracted figures from SystemVerilog LRM showing combinations of different strength drivers (left) and resulting net value (right)&#34;/&gt;
      &lt;a href=&#34;https://prbs23.com/blog/blog/posts/drive-strength-detection-in-system-verilog/sv_drive_strengths.svg&#34; itemprop=&#34;contentUrl&#34;&gt;&lt;/a&gt;
    &lt;/div&gt;
      &lt;figcaption&gt;
          &lt;p&gt;
            Extracted figures from SystemVerilog LRM showing combinations of different strength drivers (left) and resulting net value (right)
            
          &lt;/p&gt;
      &lt;/figcaption&gt;
  &lt;/figure&gt;
&lt;/div&gt;

&lt;p&gt;If the strength value of a net is determined by the relative strength values of the drivers on the net, then there must be a way to define the strength of a driving expression. In SystemVerilog, by default all driver expressions have a &lt;code&gt;strong&lt;/code&gt; strength value, which for a lot of use cases, is all you would ever need. However, the strength of logical 1 and 0 values can be individually set for both continuous assignment expressions and gate primitives by including a token of the form &lt;code&gt;(&amp;lt;strength&amp;gt;1, &amp;lt;strength&amp;gt;0)&lt;/code&gt; after the &lt;code&gt;assign&lt;/code&gt; keyword or primitive name. For example the expression &lt;code&gt;assign (strong1, weak0) foo = ~bar;&lt;/code&gt; will drive the net &lt;code&gt;foo&lt;/code&gt; with a logical value of 1 and strength of &lt;code&gt;strong&lt;/code&gt;, when &lt;code&gt;bar&lt;/code&gt; is a logical 0, and drive a logical value of 0 with strength value &lt;code&gt;weak&lt;/code&gt; when &lt;code&gt;bar&lt;/code&gt; is 1.&lt;/p&gt;
&lt;p&gt;As an example, one might use drive strength modeling when modeling an I&lt;sup&gt;2&lt;/sup&gt;C bus, which uses pull-up resistors to pull the bus high, and open drain drivers in each device to pull it low. In such a model, the pull up resistors on the bus can be simply modeled as a &lt;code&gt;pull1&lt;/code&gt; continuous assignments with a value of &lt;code&gt;1&#39;b1&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-systemverilog&#34; data-lang=&#34;systemverilog&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;assign&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;pull1&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;highz0&lt;/span&gt;) scl &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&amp;#39;b1&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Additionally, the multiple I&lt;sup&gt;2&lt;/sup&gt;C IO drivers can be modeled as driving the bus using a continuous assignment expressions with a &lt;code&gt;(highz1, strong0)&lt;/code&gt; strength expression:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;1
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-systemverilog&#34; data-lang=&#34;systemverilog&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;assign&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;highz1&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;strong0&lt;/span&gt;) scl &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; device0_scl_value;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;assign&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;highz1&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;strong0&lt;/span&gt;) scl &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; device1_scl_value;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;This is is not just nice because it&amp;rsquo;s a concise way of having the simulator figure out the interactions between devices on the bus, but it does so in a way that structurally mirrors how the circuits work. So if the simulator can do all the work of understanding the strengths of different drivers on a net, and resolving the net to the correct value, why would you need to be able to determine the strength of a net? There&amp;rsquo;s a few use cases I have actually run into, but continuing the I&lt;sup&gt;2&lt;/sup&gt;C example, one use case would be if you wanted to write an assertion to check the bus is never driven high with a &lt;code&gt;strong&lt;/code&gt; driver, since according to the specification, this should never happen.&lt;/p&gt;
&lt;h2 id=&#34;three-ways-of-detecting-drive-strength&#34;&gt;Three ways of detecting drive strength&lt;/h2&gt;
&lt;p&gt;As part of this investigation I came up with two new ways for SystemVerilog code to detect or observe the strength of a net&amp;rsquo;s driver, in addition to the initial format string based solution from Stack Overflow that kicked all this off. For all three of these approaches I will be using them to implement a generic strength detection module, that accepts the target net to detect the strength of as an inout port, and outputs a value from 0-4 indicating the drive strength of the net.&lt;/p&gt;
&lt;p&gt;The idea being if you wanted to write an assertion to check that an I&lt;sup&gt;2&lt;/sup&gt;C bus was never driven high with a strong driver, you could use the module to get the drive strength, and then put a simple assertion on that value, as shown below:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;1
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;2
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-systemverilog&#34; data-lang=&#34;systemverilog&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;wire&lt;/span&gt; scl_strength;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;strength_detect(.sig(scl), .strength(scl_strength));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;assert&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;property&lt;/span&gt;(@(scl) &lt;span style=&#34;color:#66d9ef&#34;&gt;not&lt;/span&gt;(scl &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; scl_strength &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id=&#34;the-string-formatting-approach-google-me-up-some-code&#34;&gt;The String Formatting Approach: &lt;em&gt;Google me up some code&lt;/em&gt;&lt;/h3&gt;
&lt;p&gt;As already mentioned, if you start looking into how to detect the drive strength of a net in SystemVerilog, all the recommendations I could find on the first page of Google results suggested to use the &lt;code&gt;$sformatf()&lt;/code&gt; function with the &lt;code&gt;&amp;quot;%v&amp;quot;&lt;/code&gt; format string, which creates a string representation of the net value, including the drive strength. For example a net being driven to a value of 1 with a strong driver, when passed to the &lt;code&gt;&amp;quot;%v&amp;quot;&lt;/code&gt; format string results in the string &amp;ldquo;St1&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Generalizing this approach into a module might look something like the following code. Every time the &lt;code&gt;inout&lt;/code&gt; signal &lt;code&gt;sig&lt;/code&gt; changes, we format the value of &lt;code&gt;sig&lt;/code&gt; to a string, and then do a bunch of string comparisons to figure out the drive strength of the net.&lt;/p&gt;
&lt;figure class=&#34;no-photoswipe&#34;&gt;
  &lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 1
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 2
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 3
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 4
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 5
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 6
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 7
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 8
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 9
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;10
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;11
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;12
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;13
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;14
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;15
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;16
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-systemverilog&#34; data-lang=&#34;systemverilog&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;module&lt;/span&gt; str_strength_detect (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;inout&lt;/span&gt; sig,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;output&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;logic&lt;/span&gt; [&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;] strength
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;always&lt;/span&gt; @(sig) &lt;span style=&#34;color:#66d9ef&#34;&gt;begin&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; stren_str;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    stren_str &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; $sformatf(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;%v&amp;#34;&lt;/span&gt;, sig);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; (stren_str)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;HiZ&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; strength &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;We0&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;We1&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;WeZ&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; strength &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Pu0&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Pu1&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;PuZ&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; strength &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;St0&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;St1&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;StZ&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; strength &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Su0&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Su1&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;SuZ&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; strength &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;endcase&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;endmodule&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
  
    &lt;figcaption&gt;&lt;span&gt;str_strength_detect.sv&lt;/span&gt;&lt;/figcaption&gt;
  
&lt;/figure&gt;

&lt;p&gt;Now, this does work, but I had performance concerns. SystemVerilog is good at some things, but string manipulation is not one of it&amp;rsquo;s strong suits, and I have seen simulations crawl to a halt because of particularly large or complex string formatting and manipulation tasks. We will discuss the performance of this later, but suffice it to say, when I saw this as the recommended approach to detect the strength of a net&amp;rsquo;s driver, I couldn&amp;rsquo;t help but think: There has to be a better way!&lt;/p&gt;
&lt;h3 id=&#34;sense-net-approach-using-the-simulator-against-itself&#34;&gt;&amp;ldquo;Sense Net&amp;rdquo; Approach: &lt;em&gt;Using the simulator against itself&lt;/em&gt;&lt;/h3&gt;
&lt;p&gt;After re-reading most of the LRM a few times, I eventually convinced myself that within the confines of the SystemVerilog language, there is &lt;em&gt;no&lt;/em&gt; syntax or API that returns an integer value with a net&amp;rsquo;s drive strength. However, while we can&amp;rsquo;t directly query the drive strength, we &lt;em&gt;can&lt;/em&gt; observe the effect that the strength of a driver has on net value resolution! The basic idea is to connect drivers with various strengths and opposite value to the net which we are measuring the strength of, and observe if the net value changes. The simulator&amp;rsquo;s drive strength resolution will tell us if strength of the net is stronger, equal, or weaker than the applied driver based on if the value changes, goes to &lt;code&gt;&#39;x&lt;/code&gt;, or remains the same.&lt;/p&gt;
&lt;p&gt;The trick with this, of course, is we need to do this without actually ever changing the value of the net, because that would change the result of the simulation. It turns out we can get around this by using the &lt;code&gt;cmos&lt;/code&gt; gate primitive, which is a unidirectional model element which (when enabled) will drive it&amp;rsquo;s output net with the same strength and logical value as it&amp;rsquo;s input net. This allows us to essentially create a &amp;ldquo;duplicate&amp;rdquo; net with the same driver values (logical and strength) as that of our target net, but which we can add additional drivers to without effect the real target net.&lt;/p&gt;
&lt;p&gt;After some optimization, I ended up up with with the following module with the same ports as the &lt;code&gt;str_strength_detect&lt;/code&gt; module above, but doesn&amp;rsquo;t use any strings:&lt;/p&gt;
&lt;figure class=&#34;no-photoswipe&#34;&gt;
  &lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 1
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 2
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 3
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 4
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 5
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 6
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 7
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 8
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 9
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;10
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;11
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;12
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;13
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;14
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;15
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;16
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;17
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;18
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;19
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;20
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;21
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;22
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;23
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;24
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;25
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;26
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;27
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-systemverilog&#34; data-lang=&#34;systemverilog&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;module&lt;/span&gt; sense_net_strength_detect (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;inout&lt;/span&gt; sig,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;output&lt;/span&gt; [&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;] strength
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;wire&lt;/span&gt; strong_sense;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;wire&lt;/span&gt; pull_sense;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;wire&lt;/span&gt; weak_sense;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;assign&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;strong1&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;strong0&lt;/span&gt;) strong_sense &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; (sig &lt;span style=&#34;color:#f92672&#34;&gt;===&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&amp;#39;bx) &lt;span style=&#34;color:#f92672&#34;&gt;?&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;~&lt;/span&gt;sig;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;assign&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;pull1&lt;/span&gt;  , &lt;span style=&#34;color:#66d9ef&#34;&gt;pull0&lt;/span&gt;  ) pull_sense   &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; (sig &lt;span style=&#34;color:#f92672&#34;&gt;===&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&amp;#39;bx) &lt;span style=&#34;color:#f92672&#34;&gt;?&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;~&lt;/span&gt;sig;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;assign&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;weak1&lt;/span&gt;  , &lt;span style=&#34;color:#66d9ef&#34;&gt;weak0&lt;/span&gt;  ) weak_sense   &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; (sig &lt;span style=&#34;color:#f92672&#34;&gt;===&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&amp;#39;bx) &lt;span style=&#34;color:#f92672&#34;&gt;?&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;~&lt;/span&gt;sig;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;cmos&lt;/span&gt; strong_gate(strong_sense, sig, &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;cmos&lt;/span&gt; pull_gate  (pull_sense  , sig, &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;cmos&lt;/span&gt; weak_gate  (weak_sense  , sig, &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;assign&lt;/span&gt; strength &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (sig &lt;span style=&#34;color:#f92672&#34;&gt;===&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&amp;#39;bz) &lt;span style=&#34;color:#f92672&#34;&gt;?&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    (sig &lt;span style=&#34;color:#f92672&#34;&gt;===&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&amp;#39;bx) &lt;span style=&#34;color:#f92672&#34;&gt;?&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (pull_sense   &lt;span style=&#34;color:#f92672&#34;&gt;!==&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&amp;#39;bx) &lt;span style=&#34;color:#f92672&#34;&gt;?&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (strong_sense &lt;span style=&#34;color:#f92672&#34;&gt;!==&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&amp;#39;bx) &lt;span style=&#34;color:#f92672&#34;&gt;?&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ) &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (weak_sense   &lt;span style=&#34;color:#f92672&#34;&gt;===&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&amp;#39;bx) &lt;span style=&#34;color:#f92672&#34;&gt;?&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      (pull_sense   &lt;span style=&#34;color:#f92672&#34;&gt;===&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&amp;#39;bx) &lt;span style=&#34;color:#f92672&#34;&gt;?&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    )
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  );
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;endmodule&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
  
    &lt;figcaption&gt;&lt;span&gt;sense_net_strength_detect.sv&lt;/span&gt;&lt;/figcaption&gt;
  
&lt;/figure&gt;

&lt;p&gt;Now, while this solution is almost perfect, it has one limitation: It cannot observe the difference between &lt;code&gt;supply&lt;/code&gt; and &lt;code&gt;strong&lt;/code&gt; strength values. The reason for this is that the &lt;code&gt;cmos&lt;/code&gt; primitive has one special case where the strength value is not passed through, if the input drive strength is &lt;code&gt;supply&lt;/code&gt; the output drive strength is only &lt;code&gt;strong&lt;/code&gt;. There&amp;rsquo;s a lot of cases where this limitation doesn&amp;rsquo;t matter (including the problem that got this whole thing started), and in those cases I actually really liked this solution because it&amp;rsquo;s simple and pure SystemVerilog. However, I wanted to know if there was a way around this limitation&amp;hellip;&lt;/p&gt;
&lt;h3 id=&#34;dpi-c-api-method-going-even-deeper&#34;&gt;DPI-C API Method: &lt;em&gt;Going even deeper&lt;/em&gt;&lt;/h3&gt;
&lt;p&gt;Now, as already mentioned, I believe SystemVerilog has no way to directly query the strength of a driver, however, what it does have is a well defined C interface API specification. The &amp;ldquo;Direct Programming Interface&amp;rdquo; chapters of the SystemVerilog specification defines a C API that in theory allows C code to directly interact with any SystemVerilog code running in any (complaint) simulator. One thing this API provides is a method to query the value of a net, including strength value information, using the &lt;code&gt;vpi_get_value()&lt;/code&gt; function. Since you cannot call the DPI C directly from SystemVerilog (even though you can call other linked C functions), this approach was initially less interesting to me because I would need to add yet another language to my code stack, but I was curious how this solution would look.&lt;/p&gt;
&lt;p&gt;While the SystemVerilog specification may define the DPI, it&amp;rsquo;s far from clear how the API is intended to be used. After more experimentation than I would like to admit, I ended up with the following solution: Define two C helper methods that my SystemVerilog code can call, one to get a &lt;code&gt;chandle&lt;/code&gt; (pointer) to the net of interest, and one to return an integer representation of the net&amp;rsquo;s drive strength from the DPI call:&lt;/p&gt;
&lt;p&gt;&lt;figure class=&#34;no-photoswipe&#34;&gt;
  &lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 1
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 2
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 3
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 4
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 5
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 6
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 7
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 8
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 9
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;10
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;11
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;12
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;13
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;14
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;15
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;16
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;vpiHandle &lt;span style=&#34;color:#a6e22e&#34;&gt;get_handle&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;char&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;path) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;vpi_handle_by_name&lt;/span&gt;(path, NULL);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;unsigned&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;get_strength&lt;/span&gt;(vpiHandle mod) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  s_vpi_value v &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; {vpiStrengthVal};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;vpi_get_value&lt;/span&gt;(mod, &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;v);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;switch&lt;/span&gt; (v.value.strength&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;s0 &lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; v.value.strength&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;s1 &lt;span style=&#34;color:#f92672&#34;&gt;?&lt;/span&gt; v.value.strength&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;s0 : v.value.strength&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;s1) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; vpiSupplyDrive : &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; vpiStrongDrive : &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; vpiPullDrive   : &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; vpiWeakDrive   : &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; vpiHiZ         : &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;default&lt;/span&gt;             &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
  
    &lt;figcaption&gt;&lt;span&gt;dpi_strength_detect.c&lt;/span&gt;&lt;/figcaption&gt;
  
&lt;/figure&gt;

Note that the &lt;code&gt;vpi_get_value()&lt;/code&gt; function actually returns two strength values for a net: The strongest driver on the net driving a 1 value, and the strongest value on the net driving a 0 value. To get the actual drive strength that the simulator will resolve the net to, we need to return the larger strength of &lt;code&gt;s1&lt;/code&gt; and &lt;code&gt;s0&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Using these two helper C methods, we can make a simple module that calls the &lt;code&gt;get_strength()&lt;/code&gt; C function every time the net value changes as shown below:&lt;/p&gt;
&lt;figure class=&#34;no-photoswipe&#34;&gt;
  &lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 1
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 2
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 3
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 4
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 5
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 6
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 7
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 8
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 9
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;10
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;11
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;12
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;13
&lt;/span&gt;&lt;span style=&#34;white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;14
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-systemverilog&#34; data-lang=&#34;systemverilog&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;module&lt;/span&gt; dpi_strength_detect (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;inout&lt;/span&gt; sig,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;output&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;logic&lt;/span&gt; [&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;] strength
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;DPI-C&amp;#34;&lt;/span&gt; get_handle &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;chandle&lt;/span&gt; get_handle(&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; path);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;DPI-C&amp;#34;&lt;/span&gt; get_strength &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;unsigned&lt;/span&gt; get_strength(&lt;span style=&#34;color:#66d9ef&#34;&gt;chandle&lt;/span&gt; handle);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;chandle&lt;/span&gt; h;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;initial&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;begin&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    h &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; get_handle($sformatf(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;%m.sig&amp;#34;&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;always&lt;/span&gt; @(sig) &lt;span style=&#34;color:#66d9ef&#34;&gt;begin&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    strength &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; get_strength(h);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;endmodule&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
  
    &lt;figcaption&gt;&lt;span&gt;dpi_strength_detect.sv&lt;/span&gt;&lt;/figcaption&gt;
  
&lt;/figure&gt;

&lt;p&gt;This solution works as intended, and can even differentiate between &lt;code&gt;supply&lt;/code&gt; and &lt;code&gt;strong&lt;/code&gt; drivers, but does have the complexity downside of needing to deal with and compile in C code. Most simulators provide relatively simple ways of compiling in DPI-C code, but it&amp;rsquo;s not as clean of a solution as I would have liked. If I could find a way of directly calling the DPI-C API functions from SystemVerilog code, this solution would have been more appealing.&lt;/p&gt;
&lt;h2 id=&#34;performance&#34;&gt;Performance&lt;/h2&gt;
&lt;p&gt;I started digging into this issue because I had a hunch that the string formatting approach would have too much overhead, so does this really matter? Is there really any benefit to avoiding strings?&lt;/p&gt;
&lt;p&gt;I built a very simple test bench which would cycle through all possible drive strengths with both 0 and 1 logical values 5 million times. Without a strength detection module in the model, only the multi-strength driver use to generate the signal, 5 million iterations took 14 seconds to simulate with the Xcellium Cadence simulator. The table below shows the simulation time when one strength detection module is added to the simulation for each approach I have discussed.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;No Strength Detection&lt;/th&gt;
&lt;th&gt;Format String Method&lt;/th&gt;
&lt;th&gt;Sense Net Method&lt;/th&gt;
&lt;th&gt;DPI-C Method&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Simulation Duration&lt;/td&gt;
&lt;td&gt;14 Seconds&lt;/td&gt;
&lt;td&gt;44 Seconds&lt;/td&gt;
&lt;td&gt;25.6 Seconds&lt;/td&gt;
&lt;td&gt;32 Seconds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Simulation Throughput&lt;/td&gt;
&lt;td&gt;8.571 ms/s&lt;/td&gt;
&lt;td&gt;2.737 ms/s&lt;/td&gt;
&lt;td&gt;4.675 ms/s&lt;/td&gt;
&lt;td&gt;3.75 ms/s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Relative Slowdown&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;3.14x&lt;/td&gt;
&lt;td&gt;1.83x&lt;/td&gt;
&lt;td&gt;2.28x&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The data does indeed prove out my initial expectation that string manipulation is slow. However, I was quite surprised to see that the DPI-C method was slower than my initial SystemVerilog only approach. I would have thought that the additional nets and value resolution work the simulator would have to do for the sense net approach would have out-weighed any overhead in calling out to a C library.&lt;/p&gt;
&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Overall this was an interesting deep dive into a little explored part of the SystemVerilog language. If you can get away with not needing to differentiate &lt;code&gt;strong&lt;/code&gt; from &lt;code&gt;supply&lt;/code&gt; strength values, then I would definitely recommend the &amp;ldquo;sense net&amp;rdquo; detection approach as it&amp;rsquo;s not only the fastest, but also pure SystemVerilog. If you really need to detect &lt;code&gt;supply&lt;/code&gt; strengths and the addition of two DPI-C functions isn&amp;rsquo;t problematic, then the DPI-C approach is a good choice. Either way, is better than the commonly recommended approach of using formatting the net value as a string.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>About</title>
      <link>https://prbs23.com/blog/about/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <author>prbs23@prbs23.com (prbs23)</author>
      <guid>https://prbs23.com/blog/about/</guid>
      <description>&lt;p&gt;I am a full time ASIC verification engineer, and part time electronics and software tinkerer. This blog is a place for me to write about pretty much any topic that piques my interest. Usually this ends up being a deep dive into a niche topic related to my work in ASIC design. However, I will be trying to post some content related to my non-professional software, firmware, and hardware projects. My goal here is to be informative, and I hope that someone learns something from my mistakes and the rat-holes I go down.&lt;/p&gt;
&lt;h4 id=&#34;what-is-prbs23&#34;&gt;What is PRBS23:&lt;/h4&gt;
&lt;p&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/Pseudorandom_binary_sequence&#34;&gt;Pseudorandom Binary Sequences&lt;/a&gt; are deterministic bit sequences with random-like statistical distributions, commonly generated by &lt;a href=&#34;https://en.wikipedia.org/wiki/Linear-feedback_shift_register&#34;&gt;linear-feedback shift registers&lt;/a&gt; (LFSR). PRBS patterns are useful for many data integrity validation techniques, because they are usually random enough to be used in place of arbitrary data, but the whole pattern can be recreated from a single short seed. There are many different possible PRBS sequences, typically defined by length and polynomial representation, but one commonly used in high speed SERDES like PCIe, Ethernet, etc. is PRBS23. It is 2&lt;sup&gt;23&lt;/sup&gt; bit (~1 MBit) long sequence generated from the following polynomial: x&lt;sup&gt;23&lt;/sup&gt; + x&lt;sup&gt;28&lt;/sup&gt; + 1, and can be generated using the following LFSR circuit:


&lt;div class=&#34;box &#34; &gt;
  &lt;figure  itemprop=&#34;associatedMedia&#34; itemscope itemtype=&#34;http://schema.org/ImageObject&#34;&gt;
    &lt;div class=&#34;img&#34;&gt;
      &lt;img itemprop=&#34;thumbnail&#34; src=&#34;https://prbs23.com/blog/blog/about/prbs23_lfsr.svg&#34; alt=&#34;Fibonacci LFSR implementation of PRBS23 Generator&#34;/&gt;
      &lt;a href=&#34;https://prbs23.com/blog/blog/about/prbs23_lfsr.svg&#34; itemprop=&#34;contentUrl&#34;&gt;&lt;/a&gt;
    &lt;/div&gt;
      &lt;figcaption&gt;
          &lt;p&gt;
            Fibonacci LFSR implementation of PRBS23 Generator
            
          &lt;/p&gt;
      &lt;/figcaption&gt;
  &lt;/figure&gt;
&lt;/div&gt;
&lt;/p&gt;
&lt;p&gt;As far as it&amp;rsquo;s relation to this blog, the name is just as random as a PRBS23. Many things here are related, but not in an obvious way&amp;hellip;&lt;/p&gt;
</description>
    </item>
    
  </channel>
</rss>

