<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.2.2">Jekyll</generator><link href="https://blog.verificationgentleman.com/feed.xml" rel="self" type="application/atom+xml" /><link href="https://blog.verificationgentleman.com/" rel="alternate" type="text/html" /><updated>2026-04-08T22:33:29+02:00</updated><id>https://blog.verificationgentleman.com/feed.xml</id><title type="html">Verification Gentleman Blog</title><subtitle>Constrained random thoughts on SystemVerilog and more</subtitle><author><name>Tudor Timi</name></author><entry><title type="html">Coverage Extensibility in SystemVerilog-2023</title><link href="https://blog.verificationgentleman.com/2026/03/01/coverage-extensibility-in-systemverilog-2023.html" rel="alternate" type="text/html" title="Coverage Extensibility in SystemVerilog-2023" /><published>2026-03-01T20:46:00+01:00</published><updated>2026-03-01T20:46:00+01:00</updated><id>https://blog.verificationgentleman.com/2026/03/01/coverage-extensibility-in-systemverilog-2023</id><content type="html" xml:base="https://blog.verificationgentleman.com/2026/03/01/coverage-extensibility-in-systemverilog-2023.html"><![CDATA[<p>Quite a while back I wrote a series of posts about coverage extensibility in SystemVerilog.
In the <a href="/2015/06/29/some-ideas-on-coverage-extensibility.html">first post</a> we looked at how to use policy classes to implement extensible coverage collectors,
where ignore bins can be tweaked via class parameters.
The <a href="/2015/06/29/some-more-ideas-on-coverage-extensibility.html">second post</a> explored a dynamic flavor of this approach,
using constructor arguments instead.
Finally, the <a href="/2015/06/29/even-more-ideas-on-coverage-extensibility.html">third post</a> tied everything together by looking at how these approaches interact with UVM and the factory.</p>

<p>All of that was necessary because SystemVerilog didn’t have a way to extend coverage groups natively.
In contrast, the e language makes it possible to modify coverage definitions from anywhere in the verification environment.
Getting anything similar in SystemVerilog required quite a bit of pre-planning and infrastructure code.</p>

<p>With the release of IEEE Std 1800-2023,
SystemVerilog finally got a new language feature in this area.
Section <em>19.4.1 Embedded covergroup inheritance</em> describes that
it’s now possible for a covergroup to extend another covergroup.
This is great news,
if it means we can express what we need without all of the scaffolding we had to put in place before.</p>

<p>In this post, let’s have a look at what <code class="language-plaintext highlighter-rouge">covergroup extends</code> brings to the table and see how much of what I wrote back then has become obsolete.</p>

<h2 id="the-original-example">The Original Example</h2>

<p>Let’s start by revisiting the example from the original post series.
We had a simple RISC CPU that supported four operations (<code class="language-plaintext highlighter-rouge">ADD</code>, <code class="language-plaintext highlighter-rouge">SUB</code>, <code class="language-plaintext highlighter-rouge">MUL</code> and <code class="language-plaintext highlighter-rouge">DIV</code>) on eight registers (<code class="language-plaintext highlighter-rouge">R0</code> to <code class="language-plaintext highlighter-rouge">R7</code>).
Here’s what our initial coverage looked like:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">class</span> <span class="n">coverage_collector</span><span class="p">;</span>

    <span class="k">covergroup</span> <span class="n">cg</span> <span class="k">with</span> <span class="k">function</span> <span class="n">sample</span><span class="p">(</span><span class="n">operation_e</span> <span class="n">operation</span><span class="p">,</span> <span class="n">register_e</span> <span class="n">op1</span><span class="p">,</span> <span class="n">register_e</span> <span class="n">op2</span><span class="p">,</span> <span class="n">register_e</span> <span class="n">dest</span><span class="p">);</span>
        <span class="k">coverpoint</span> <span class="n">operation</span><span class="p">;</span>
        <span class="k">coverpoint</span> <span class="n">op1</span><span class="p">;</span>
        <span class="k">coverpoint</span> <span class="n">op2</span><span class="p">;</span>
        <span class="k">coverpoint</span> <span class="n">dest</span><span class="p">;</span>

        <span class="n">operation_vs_op1</span> <span class="o">:</span> <span class="k">cross</span> <span class="n">operation</span><span class="p">,</span> <span class="n">op1</span><span class="p">;</span>
        <span class="n">operation_vs_op2</span> <span class="o">:</span> <span class="k">cross</span> <span class="n">operation</span><span class="p">,</span> <span class="n">op2</span><span class="p">;</span>
        <span class="n">operation_vs_dest</span> <span class="o">:</span> <span class="k">cross</span> <span class="n">operation</span><span class="p">,</span> <span class="n">dest</span><span class="p">;</span>

        <span class="n">same_reg_both_ops</span> <span class="o">:</span> <span class="k">coverpoint</span> <span class="p">(</span><span class="n">op1</span> <span class="o">==</span> <span class="n">op2</span><span class="p">);</span>
        <span class="n">same_reg_op1_and_dest</span> <span class="o">:</span> <span class="k">coverpoint</span> <span class="p">(</span><span class="n">op1</span> <span class="o">==</span> <span class="n">dest</span><span class="p">);</span>
        <span class="n">same_reg_op2_and_dest</span> <span class="o">:</span> <span class="k">coverpoint</span> <span class="p">(</span><span class="n">op2</span> <span class="o">==</span> <span class="n">dest</span><span class="p">);</span>
        <span class="n">same_reg_both_ops_and_dest</span> <span class="o">:</span> <span class="k">coverpoint</span> <span class="p">(</span><span class="n">op1</span> <span class="o">==</span> <span class="n">dest</span> <span class="o">&amp;&amp;</span> <span class="n">op2</span> <span class="o">==</span> <span class="n">dest</span><span class="p">);</span>

        <span class="n">option</span><span class="p">.</span><span class="n">per_instance</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
    <span class="k">endgroup</span>

    <span class="c1">// ...</span>
<span class="k">endclass</span>
</code></pre></div></div>

<p>Notice that we’re now using the <code class="language-plaintext highlighter-rouge">with function sample(...)</code> construct.
This allows us to avoid polluting our class with member variables that don’t actually represent the object’s state,
but are just used for “argument passing” to the coverpoint expressions.</p>

<h2 id="variant-with-fewer-operations">Variant with Fewer Operations</h2>

<p>The original posts introduced a variant of the CPU which dropped the <code class="language-plaintext highlighter-rouge">MUL</code> and <code class="language-plaintext highlighter-rouge">DIV</code> instructions.
They showed how to customize the coverage model for it,
by using hooks to control the contents of the <code class="language-plaintext highlighter-rouge">operation</code> coverpoint’s ignore bins.</p>

<p>With <code class="language-plaintext highlighter-rouge">covergroup extends</code>, this becomes really straightforward:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">class</span> <span class="n">no_mul_div_coverage_collector</span> <span class="k">extends</span> <span class="n">coverage_collector</span><span class="p">;</span>

    <span class="k">covergroup</span> <span class="k">extends</span> <span class="n">cg</span><span class="p">;</span>
        <span class="k">coverpoint</span> <span class="n">operation</span> <span class="o">{</span>
            <span class="k">ignore_bins</span> <span class="n">mul_div</span> <span class="o">=</span> <span class="o">{</span> <span class="n">MUL</span><span class="p">,</span> <span class="n">DIV</span> <span class="o">}</span><span class="p">;</span>
        <span class="o">}</span>
    <span class="k">endgroup</span>

<span class="k">endclass</span>
</code></pre></div></div>

<p>We can now customize the ignore bins without having to set up any infrastructure for future extensions.
Notice that we don’t need to specify the arguments for <code class="language-plaintext highlighter-rouge">sample(...)</code> again.
The extended covergroup inherits the signature from the base, so no need for boilerplate code.</p>

<p>But here’s where things get tricky.
If we compile and run this code, we’ll notice something interesting: the crosses still include all the multiplication and division bins.
This is because the cross definitions in the base class still use the base class’s definition of the <code class="language-plaintext highlighter-rouge">operation</code> coverpoint, not our refined version.
Initially, I thought that this was a bug in the tool,
but actually things are working as specified in the standard:</p>

<blockquote>
  <p>Even if a coverage point in the base covergroup does not contribute to the computation,
a cross […] in the base covergroup that includes that base coverpoint still contributes to the computation
unless there is a cross with the same name in the derived covergroup.</p>
</blockquote>

<p>To fix this, we need to redeclare the crosses:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">class</span> <span class="n">no_mul_div_coverage_collector</span> <span class="k">extends</span> <span class="n">coverage_collector</span><span class="p">;</span>

    <span class="k">covergroup</span> <span class="k">extends</span> <span class="n">cg</span><span class="p">;</span>
        <span class="c1">// ...</span>

        <span class="n">operation_vs_op1</span> <span class="o">:</span> <span class="k">cross</span> <span class="n">operation</span><span class="p">,</span> <span class="n">op1</span><span class="p">;</span>
        <span class="n">operation_vs_op2</span> <span class="o">:</span> <span class="k">cross</span> <span class="n">operation</span><span class="p">,</span> <span class="n">op2</span><span class="p">;</span>
        <span class="n">operation_vs_dest</span> <span class="o">:</span> <span class="k">cross</span> <span class="n">operation</span><span class="p">,</span> <span class="n">dest</span><span class="p">;</span>
    <span class="k">endgroup</span>

<span class="k">endclass</span>
</code></pre></div></div>

<p>This feels a bit unsatisfying.
From the point of view of class inheritance, coverpoints behave like non‑virtual functions:
the derived coverpoint hides the original <code class="language-plaintext highlighter-rouge">operation</code> definition in the derived class’s scope rather than overriding it for the base class.
Since the base class’s crosses still reference the original <code class="language-plaintext highlighter-rouge">operation</code>,
we have to hide those too by redeclaring them.</p>

<p>In e,
when extending a coverage item,
the crosses that reference that item use the updated definition.
The folks on the IEEE 1800 committee could have used the e language as a reference when designing embedded covergroup inheritance,
but,
for reasons I don’t know,
they decided to implement different semantics.
I can’t think of any use case where keeping base crosses bound to base coverpoints is actually helpful.
The example above shows the opposite.
If you know of a situation where this behavior is desirable, please tell me in a comment.</p>

<h2 id="variant-with-fewer-registers-more-of-the-same">Variant with Fewer Registers: More of the Same</h2>

<p>Let’s look at another variant from the original post series,
where our CPU only implements registers <code class="language-plaintext highlighter-rouge">R0</code> through <code class="language-plaintext highlighter-rouge">R3</code>.
We have to adapt our coverage to ignore the higher-numbered registers.
Following the same pattern as before, we extend the covergroup and add ignore bins:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">class</span> <span class="n">fewer_regs_coverage_collector</span> <span class="k">extends</span> <span class="n">coverage_collector</span><span class="p">;</span>

    <span class="k">covergroup</span> <span class="k">extends</span> <span class="n">cg</span><span class="p">;</span>
        <span class="k">coverpoint</span> <span class="n">op1</span> <span class="o">{</span>
            <span class="k">ignore_bins</span> <span class="n">r4_to_r7</span> <span class="o">=</span> <span class="o">{</span> <span class="n">R4</span><span class="p">,</span> <span class="n">R5</span><span class="p">,</span> <span class="n">R6</span><span class="p">,</span> <span class="n">R7</span> <span class="o">}</span><span class="p">;</span>
        <span class="o">}</span>
        <span class="k">coverpoint</span> <span class="n">op2</span> <span class="o">{</span>
            <span class="k">ignore_bins</span> <span class="n">r4_to_r7</span> <span class="o">=</span> <span class="o">{</span> <span class="n">R4</span><span class="p">,</span> <span class="n">R5</span><span class="p">,</span> <span class="n">R6</span><span class="p">,</span> <span class="n">R7</span> <span class="o">}</span><span class="p">;</span>
        <span class="o">}</span>
        <span class="k">coverpoint</span> <span class="n">dest</span> <span class="o">{</span>
            <span class="k">ignore_bins</span> <span class="n">r4_to_r7</span> <span class="o">=</span> <span class="o">{</span> <span class="n">R4</span><span class="p">,</span> <span class="n">R5</span><span class="p">,</span> <span class="n">R6</span><span class="p">,</span> <span class="n">R7</span> <span class="o">}</span><span class="p">;</span>
        <span class="o">}</span>

        <span class="n">operation_vs_op1</span> <span class="o">:</span> <span class="k">cross</span> <span class="n">operation</span><span class="p">,</span> <span class="n">op1</span><span class="p">;</span>
        <span class="n">operation_vs_op2</span> <span class="o">:</span> <span class="k">cross</span> <span class="n">operation</span><span class="p">,</span> <span class="n">op2</span><span class="p">;</span>
        <span class="n">operation_vs_dest</span> <span class="o">:</span> <span class="k">cross</span> <span class="n">operation</span><span class="p">,</span> <span class="n">dest</span><span class="p">;</span>
    <span class="k">endgroup</span>

<span class="k">endclass</span>
</code></pre></div></div>

<p>Again, we need to redeclare all the crosses that involve the modified coverpoints.
The whole point of using <code class="language-plaintext highlighter-rouge">covergroup extends</code> was to avoid having to write too much code.
Granted, this is boilerplate code,
so it’s simpler than having to build the infrastructure for extensibility,
but forgetting to redeclare crosses is easy to overlook
and can potentially create work for us in the future.</p>

<h2 id="combining-variants-where-things-break-down">Combining Variants: Where Things Break Down</h2>

<p>Now here’s where we hit a wall.
In the original post series, we looked at a final CPU variant that had both limitations:
only four registers <em>and</em> only addition and subtraction.
With single inheritance, we can’t cleanly combine both extensions.</p>

<p>We <em>could</em> create a new class that extends one of them and adds the other ignores.
For example:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">class</span> <span class="n">fewer_regs_no_mul_div_coverage_collector</span> <span class="k">extends</span> <span class="n">no_mul_div_coverage_collector</span><span class="p">;</span>

    <span class="k">covergroup</span> <span class="k">extends</span> <span class="n">cg</span><span class="p">;</span>
        <span class="k">coverpoint</span> <span class="n">op1</span> <span class="o">{</span>
            <span class="k">ignore_bins</span> <span class="n">r4_to_r7</span> <span class="o">=</span> <span class="o">{</span> <span class="n">R4</span><span class="p">,</span> <span class="n">R5</span><span class="p">,</span> <span class="n">R6</span><span class="p">,</span> <span class="n">R7</span> <span class="o">}</span><span class="p">;</span>
        <span class="o">}</span>
        <span class="k">coverpoint</span> <span class="n">op2</span> <span class="o">{</span>
            <span class="k">ignore_bins</span> <span class="n">r4_to_r7</span> <span class="o">=</span> <span class="o">{</span> <span class="n">R4</span><span class="p">,</span> <span class="n">R5</span><span class="p">,</span> <span class="n">R6</span><span class="p">,</span> <span class="n">R7</span> <span class="o">}</span><span class="p">;</span>
        <span class="o">}</span>
        <span class="k">coverpoint</span> <span class="n">dest</span> <span class="o">{</span>
            <span class="k">ignore_bins</span> <span class="n">r4_to_r7</span> <span class="o">=</span> <span class="o">{</span> <span class="n">R4</span><span class="p">,</span> <span class="n">R5</span><span class="p">,</span> <span class="n">R6</span><span class="p">,</span> <span class="n">R7</span> <span class="o">}</span><span class="p">;</span>
        <span class="o">}</span>

        <span class="n">operation_vs_op1</span> <span class="o">:</span> <span class="k">cross</span> <span class="n">operation</span><span class="p">,</span> <span class="n">op1</span><span class="p">;</span>
        <span class="n">operation_vs_op2</span> <span class="o">:</span> <span class="k">cross</span> <span class="n">operation</span><span class="p">,</span> <span class="n">op2</span><span class="p">;</span>
        <span class="n">operation_vs_dest</span> <span class="o">:</span> <span class="k">cross</span> <span class="n">operation</span><span class="p">,</span> <span class="n">dest</span><span class="p">;</span>
    <span class="k">endgroup</span>

<span class="k">endclass</span>
</code></pre></div></div>

<p>But this just means duplicating code.
We’ve essentially reimplemented the functionality in <code class="language-plaintext highlighter-rouge">fewer_regs_coverage_collector</code>.
Of course, in this case we could switch where we start the inheritance tree, by creating a <code class="language-plaintext highlighter-rouge">no_mul_div_fewer_regs_coverage_collector</code> which extends <code class="language-plaintext highlighter-rouge">fewer_regs_coverage_collector</code>,
because this way we have less code to duplicate.
This is still a compromise, though.
The problem isn’t only the amount of duplicated code,
but also the fact that we have to remember to look for it if we ever need to change it.</p>

<p>We could try to use the mixin pattern (which I’ve written about <a href="/2014/09/03/emulating-multiple-inheritance-in-system-verilog.html">before</a>) to work around this,
but that comes with its own set of problems and added complexity.</p>

<p>The dynamic variant with policy classes that I described in the <a href="/2015/06/29/some-more-ideas-on-coverage-extensibility.html">second post</a> of the original series handled this more elegantly.
It allowed us to pass multiple policy objects and compose their filtering behavior.
This is a classic example of how inheritance can’t beat composition.</p>

<h2 id="when-requirements-change-redeclaring-means-rewriting-from-scratch">When Requirements Change: Redeclaring Means Rewriting From Scratch</h2>

<p>The problems don’t stop at crosses.
There’s another subtlety that makes modifying existing coverpoints more painful than it looks.</p>

<p>Let’s say that during development, the requirements for our CPU change such that <code class="language-plaintext highlighter-rouge">R0</code> is now a hardwired zero register.
This means it can never be the destination of an instruction.
We have to update the base coverage model to capture this:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">class</span> <span class="n">coverage_collector</span><span class="p">;</span>

    <span class="k">covergroup</span> <span class="n">cg</span> <span class="k">with</span> <span class="k">function</span> <span class="n">sample</span><span class="p">(</span><span class="n">operation_e</span> <span class="n">operation</span><span class="p">,</span> <span class="n">register_e</span> <span class="n">op1</span><span class="p">,</span> <span class="n">register_e</span> <span class="n">op2</span><span class="p">,</span> <span class="n">register_e</span> <span class="n">dest</span><span class="p">);</span>
        <span class="k">coverpoint</span> <span class="n">dest</span> <span class="o">{</span>
            <span class="k">ignore_bins</span> <span class="n">r0_cannot_be_dest</span> <span class="o">=</span> <span class="o">{</span> <span class="n">R0</span> <span class="o">}</span><span class="p">;</span>
        <span class="o">}</span>

        <span class="c1">// ...</span>
    <span class="k">endgroup</span>

    <span class="c1">// ...</span>
<span class="k">endclass</span>
</code></pre></div></div>

<p>For the <code class="language-plaintext highlighter-rouge">fewer_regs_coverage_collector</code> class,
if we were to check the bins of the <code class="language-plaintext highlighter-rouge">dest</code> coverpoint,
we would unexpectedly find that <code class="language-plaintext highlighter-rouge">R0</code> is still included.
This is because we’re redeclaring the coverpoint:
we’re not <em>extending</em> what’s already there, we’re replacing it entirely.
There’s no way to refer to the existing bins from the base coverpoint and just add to them.
We have to write it all out again:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">class</span> <span class="n">fewer_regs_coverage_collector</span> <span class="k">extends</span> <span class="n">coverage_collector</span><span class="p">;</span>

    <span class="k">covergroup</span> <span class="k">extends</span> <span class="n">cg</span><span class="p">;</span>
        <span class="k">coverpoint</span> <span class="n">dest</span> <span class="o">{</span>
            <span class="k">ignore_bins</span> <span class="n">r0_cannot_be_dest</span> <span class="o">=</span> <span class="o">{</span> <span class="n">R0</span> <span class="o">}</span><span class="p">;</span>
            <span class="k">ignore_bins</span> <span class="n">r4_to_r7</span> <span class="o">=</span> <span class="o">{</span> <span class="n">R4</span><span class="p">,</span> <span class="n">R5</span><span class="p">,</span> <span class="n">R6</span><span class="p">,</span> <span class="n">R7</span> <span class="o">}</span><span class="p">;</span>
        <span class="o">}</span>

        <span class="c1">// ...</span>
    <span class="k">endgroup</span>

<span class="k">endclass</span>
</code></pre></div></div>

<p>In e, the <code class="language-plaintext highlighter-rouge">prev</code> keyword lets us reference the previous (base) definition of a cover item,
so we can include its existing bin expressions without repeating them.
This is another area where the folks on the IEEE 1800 committee could have taken a page from the e language book,
but SystemVerilog has no equivalent construct.
When we redeclare a coverpoint,
we start from a blank slate.</p>

<p>For the case where we have both fewer registers and no <code class="language-plaintext highlighter-rouge">MUL</code> and <code class="language-plaintext highlighter-rouge">DIV</code> operations,
since we copied and pasted code from <code class="language-plaintext highlighter-rouge">fewer_regs_coverage_collector</code>,
we have to fix it there as well:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">class</span> <span class="n">fewer_regs_no_mul_div_coverage_collector</span> <span class="k">extends</span> <span class="n">no_mul_div_coverage_collector</span><span class="p">;</span>

    <span class="k">covergroup</span> <span class="k">extends</span> <span class="n">cg</span><span class="p">;</span>
        <span class="k">coverpoint</span> <span class="n">dest</span> <span class="o">{</span>
            <span class="k">ignore_bins</span> <span class="n">r0_cannot_be_dest</span> <span class="o">=</span> <span class="o">{</span> <span class="n">R0</span> <span class="o">}</span><span class="p">;</span>
            <span class="k">ignore_bins</span> <span class="n">r4_to_r7</span> <span class="o">=</span> <span class="o">{</span> <span class="n">R4</span><span class="p">,</span> <span class="n">R5</span><span class="p">,</span> <span class="n">R6</span><span class="p">,</span> <span class="n">R7</span> <span class="o">}</span><span class="p">;</span>
        <span class="o">}</span>

        <span class="c1">// ...</span>
    <span class="k">endgroup</span>

<span class="k">endclass</span>
</code></pre></div></div>

<p>Because the change was fresh,
it was easy to remember to update this code.
If a lot of time had passed from when we originally wrote it,
we might not have been so lucky.</p>

<p>The same issue applies to crosses.
If any of the crosses that we were redeclaring had its own ignore bins,
we’d have to duplicate those too.
The need to redeclare coverage group members is actually more problematic than we initially thought.
(I would have liked to show an example of this by having some ignore bins defined in a cross,
but the tool which supports <code class="language-plaintext highlighter-rouge">covergroup extends</code> doesn’t have good support for defining cross bins.)</p>

<h2 id="adding-new-coverage-where-covergroup-extends-shines">Adding New Coverage: Where <code class="language-plaintext highlighter-rouge">covergroup extends</code> Shines</h2>

<p>So far we’ve been looking at the rough edges.
Let me end on a more positive note,
because <code class="language-plaintext highlighter-rouge">covergroup extends</code> is genuinely well-suited for one thing:
adding coverage items that are missing from the base class entirely.</p>

<p>Let’s assume that the original coverage model is part of a reusable library for CPU verification,
which we can’t modify.
The <code class="language-plaintext highlighter-rouge">same_reg_*</code> coverpoints only track whether two registers happen to be the same,
but they’re never crossed against the operation type and the register value.
That’s potentially interesting coverage, for example
“Does a <code class="language-plaintext highlighter-rouge">SUB</code> instruction ever write back into <code class="language-plaintext highlighter-rouge">R1</code> after it read the first operand also from <code class="language-plaintext highlighter-rouge">R1</code>?”.</p>

<p>We can layer these crosses on top without touching the base class at all:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">class</span> <span class="n">enhanced_coverage_collector</span> <span class="k">extends</span> <span class="n">coverage_collector</span><span class="p">;</span>

    <span class="k">covergroup</span> <span class="k">extends</span> <span class="n">cg</span><span class="p">;</span>
        <span class="n">operation_vs_same_op1_and_op2</span> <span class="o">:</span> <span class="k">cross</span> <span class="n">operation</span><span class="p">,</span> <span class="n">op1</span><span class="p">,</span> <span class="n">same_reg_both_ops</span><span class="p">;</span>
        <span class="n">operation_vs_same_dest_and_op1</span> <span class="o">:</span> <span class="k">cross</span> <span class="n">operation</span><span class="p">,</span> <span class="n">dest</span><span class="p">,</span> <span class="n">same_reg_op1_and_dest</span><span class="p">;</span>
        <span class="n">operation_vs_same_dest_and_op2</span> <span class="o">:</span> <span class="k">cross</span> <span class="n">operation</span><span class="p">,</span> <span class="n">dest</span><span class="p">,</span> <span class="n">same_reg_op2_and_dest</span><span class="p">;</span>
        <span class="n">operation_vs_same_dest_and_both_ops</span> <span class="o">:</span> <span class="k">cross</span> <span class="n">operation</span><span class="p">,</span> <span class="n">dest</span><span class="p">,</span> <span class="n">same_reg_both_ops_and_dest</span><span class="p">;</span>
    <span class="k">endgroup</span>

<span class="k">endclass</span>
</code></pre></div></div>

<p>Without <code class="language-plaintext highlighter-rouge">covergroup extends</code>, we would have had to rewrite the entire covergroup:
all its coverpoint definitions, all their bins, and all its crosses.</p>

<p>(You might notice that the crosses look a bit unusual.
Ideally we would cross <code class="language-plaintext highlighter-rouge">op1</code> directly with <code class="language-plaintext highlighter-rouge">op2</code>, or <code class="language-plaintext highlighter-rouge">dest</code> with <code class="language-plaintext highlighter-rouge">op1</code>,
and filter to keep only the bins where they are equal.
I tried doing exactly that,
using the <code class="language-plaintext highlighter-rouge">with</code> syntax from section <em>19.6.1.2 Cross bin with covergroup expressions</em>.
When this didn’t work, I tried to instead cross with the boolean <code class="language-plaintext highlighter-rouge">same_reg_*</code> coverpoints
and to use the older <code class="language-plaintext highlighter-rouge">binsof ... intersect</code> syntax from section <em>19.6.1 Defining cross coverage bins</em>.
This also didn’t work,
so I stopped trying to filter out the cases where the registers are not the same.
The result is not as clean,
but it’s good enough for the purpose of demonstrating <code class="language-plaintext highlighter-rouge">covergroup extends</code>.)</p>

<h2 id="conclusion">Conclusion</h2>

<p>So how much of what I wrote back in 2015 has become obsolete?
Pretty much none of it,
as it turns out.</p>

<p><em>Embedded covergroup inheritance</em> is a welcome addition to SystemVerilog.
It’s a good feature,
but some questionable design decisions stop it from being great.</p>

<p>For adding new coverpoints and crosses on top of a base model, it works cleanly,
with minimal boilerplate,
and no need to touch the original class.
This use case alone makes it worth knowing about.</p>

<p>For modifying existing coverage, however, the story is less rosy.
Redeclaring a coverpoint replaces it entirely and there is no way to build on what the base already defined.
Also, since crosses don’t automatically track changes to the coverpoints they are composed of,
any cross that involves a redeclared coverpoint must itself be redeclared.</p>

<p>For composable, modification-heavy scenarios, the policy class approach from the original post series still holds its ground.
The two techniques are best treated as complements rather than replacements for each other.</p>

<p>One practical caveat: simulator support for <code class="language-plaintext highlighter-rouge">covergroup extends</code> is still far from universal.
If you want to experiment with the examples in this post,
they might not work in your tool of choice.
If that’s the case,
I’d encourage you to ask your EDA vendor to implement this feature.
The more teams make the request, the higher the chances it gets worked on.</p>

<p>As always, you can find the code for this post on <a href="https://github.com/verification-gentleman-blog/coverage-extensibility-in-systemverilog-2023">GitHub</a>.
Thanks for reading and see you next time!</p>]]></content><author><name>Tudor Timi</name></author><category term="SystemVerilog" /><summary type="html"><![CDATA[Quite a while back I wrote a series of posts about coverage extensibility in SystemVerilog. In the first post we looked at how to use policy classes to implement extensible coverage collectors, where ignore bins can be tweaked via class parameters. The second post explored a dynamic flavor of this approach, using constructor arguments instead. Finally, the third post tied everything together by looking at how these approaches interact with UVM and the factory.]]></summary></entry><entry><title type="html">Creating UVM Tests Dynamically</title><link href="https://blog.verificationgentleman.com/2023/01/08/creating-uvm-tests-dynamically.html" rel="alternate" type="text/html" title="Creating UVM Tests Dynamically" /><published>2023-01-08T20:20:00+01:00</published><updated>2023-01-08T20:20:00+01:00</updated><id>https://blog.verificationgentleman.com/2023/01/08/creating-uvm-tests-dynamically</id><content type="html" xml:base="https://blog.verificationgentleman.com/2023/01/08/creating-uvm-tests-dynamically.html"><![CDATA[<p>Everyone who uses UVM knows that using the library ofter requires large amounts of <a href="https://en.wikipedia.org/wiki/Boilerplate_code">boilerplate code</a>.
Tests are no exception.</p>

<p>A UVM test usually starts a certain sequence during its run phase
(but other run-time phases could also be used).
Let’s assume that we have three sequences:
<code class="language-plaintext highlighter-rouge">some_sequence</code>,
<code class="language-plaintext highlighter-rouge">some_other_sequence</code>
and <code class="language-plaintext highlighter-rouge">yet_another_sequence</code>,
which we each want to start from its own test.</p>

<p>Here’s an example of a test that starts <code class="language-plaintext highlighter-rouge">some_sequence</code>:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">class</span> <span class="n">test_that_executes_some_sequence</span> <span class="k">extends</span> <span class="n">uvm_test</span><span class="p">;</span>

  <span class="k">function</span> <span class="k">new</span><span class="p">(</span><span class="kt">string</span> <span class="n">name</span><span class="p">,</span> <span class="n">uvm_component</span> <span class="n">parent</span><span class="p">);</span>
    <span class="k">super</span><span class="p">.</span><span class="k">new</span><span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="n">parent</span><span class="p">);</span>
  <span class="k">endfunction</span>

  <span class="kt">virtual</span> <span class="k">task</span> <span class="n">run_phase</span><span class="p">(</span><span class="n">uvm_phase</span> <span class="n">phase</span><span class="p">);</span>
    <span class="n">some_sequence</span> <span class="n">seq</span> <span class="o">=</span> <span class="n">some_sequence</span><span class="o">::</span><span class="n">type_id</span><span class="o">::</span><span class="n">create</span><span class="p">(</span><span class="s">"seq"</span><span class="p">,</span> <span class="k">this</span><span class="p">);</span>
    <span class="n">phase</span><span class="p">.</span><span class="n">raise_objection</span><span class="p">(</span><span class="k">this</span><span class="p">);</span>
    <span class="n">seq</span><span class="p">.</span><span class="n">start</span><span class="p">(</span><span class="k">null</span><span class="p">);</span>
    <span class="n">phase</span><span class="p">.</span><span class="n">drop_objection</span><span class="p">(</span><span class="k">this</span><span class="p">);</span>
  <span class="k">endtask</span>

  <span class="cp">`uvm_component_utils</span><span class="p">(</span><span class="n">test_that_executes_some_sequence</span><span class="p">)</span>

<span class="k">endclass</span>
</code></pre></div></div>

<p>A test that starts <code class="language-plaintext highlighter-rouge">some_other_sequence</code> is:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">class</span> <span class="n">test_that_executes_some_other_sequence</span> <span class="k">extends</span> <span class="n">uvm_test</span><span class="p">;</span>

  <span class="k">function</span> <span class="k">new</span><span class="p">(</span><span class="kt">string</span> <span class="n">name</span><span class="p">,</span> <span class="n">uvm_component</span> <span class="n">parent</span><span class="p">);</span>
    <span class="k">super</span><span class="p">.</span><span class="k">new</span><span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="n">parent</span><span class="p">);</span>
  <span class="k">endfunction</span>

  <span class="kt">virtual</span> <span class="k">task</span> <span class="n">run_phase</span><span class="p">(</span><span class="n">uvm_phase</span> <span class="n">phase</span><span class="p">);</span>
    <span class="n">some_other_sequence</span> <span class="n">seq</span> <span class="o">=</span> <span class="n">some_other_sequence</span><span class="o">::</span><span class="n">type_id</span><span class="o">::</span><span class="n">create</span><span class="p">(</span><span class="s">"seq"</span><span class="p">,</span> <span class="k">this</span><span class="p">);</span>
    <span class="n">phase</span><span class="p">.</span><span class="n">raise_objection</span><span class="p">(</span><span class="k">this</span><span class="p">);</span>
    <span class="n">seq</span><span class="p">.</span><span class="n">start</span><span class="p">(</span><span class="k">null</span><span class="p">);</span>
    <span class="n">phase</span><span class="p">.</span><span class="n">drop_objection</span><span class="p">(</span><span class="k">this</span><span class="p">);</span>
  <span class="k">endtask</span>

  <span class="cp">`uvm_component_utils</span><span class="p">(</span><span class="n">test_that_executes_some_other_sequence</span><span class="p">)</span>

<span class="k">endclass</span>
</code></pre></div></div>

<p>Finally, a test that starts <code class="language-plaintext highlighter-rouge">yet_another_sequence</code> is:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">class</span> <span class="n">test_that_executes_yet_another_sequence</span> <span class="k">extends</span> <span class="n">uvm_test</span><span class="p">;</span>

  <span class="k">function</span> <span class="k">new</span><span class="p">(</span><span class="kt">string</span> <span class="n">name</span><span class="p">,</span> <span class="n">uvm_component</span> <span class="n">parent</span><span class="p">);</span>
    <span class="k">super</span><span class="p">.</span><span class="k">new</span><span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="n">parent</span><span class="p">);</span>
  <span class="k">endfunction</span>

  <span class="kt">virtual</span> <span class="k">task</span> <span class="n">run_phase</span><span class="p">(</span><span class="n">uvm_phase</span> <span class="n">phase</span><span class="p">);</span>
    <span class="n">yet_another_sequence</span> <span class="n">seq</span> <span class="o">=</span> <span class="n">yet_another_sequence</span><span class="o">::</span><span class="n">type_id</span><span class="o">::</span><span class="n">create</span><span class="p">(</span><span class="s">"seq"</span><span class="p">,</span> <span class="k">this</span><span class="p">);</span>
    <span class="n">phase</span><span class="p">.</span><span class="n">raise_objection</span><span class="p">(</span><span class="k">this</span><span class="p">);</span>
    <span class="n">seq</span><span class="p">.</span><span class="n">start</span><span class="p">(</span><span class="k">null</span><span class="p">);</span>
    <span class="n">phase</span><span class="p">.</span><span class="n">drop_objection</span><span class="p">(</span><span class="k">this</span><span class="p">);</span>
  <span class="k">endtask</span>

  <span class="cp">`uvm_component_utils</span><span class="p">(</span><span class="n">test_that_executes_yet_another_sequence</span><span class="p">)</span>

<span class="k">endclass</span>
</code></pre></div></div>

<p>That’s a pretty impressive amount of code just to say
“start each of the three sequences in its own test”.
The amount is not necessarily the problem,
but coupled with the fact that there is a lot of duplication makes it become one.
It’s not immediately obvious whether the three files differ by more than just the sequence and test names
or whether there are any hidden tweaks which make them behave slightly differently.</p>

<p>We would like to achieve something like the following pseudo-code:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>create_test_that_starts(some_sequence)
create_test_that_starts(some_other_sequence)
create_test_that_starts(yet_another_sequence)
</code></pre></div></div>

<p>This way we know that the tests only differ in the sequence being started.
Even cooler would be to be able to specify tests using loops:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>for seq in [some_sequence, some_other_sequence, yet_another_sequence]:
    create_test_that_starts(seq)
</code></pre></div></div>

<p>This matches the natural language description of our problem statement:
“start each of the three sequences in its own test”.</p>

<p>One possible solution would be to use macros,
but these generally suffer from an array of issues,
like lack of clarity as to how and where they should be used,
poor error messages when writing code that doesn’t compile,
lack of debug capabilities,
etc.</p>

<p>Another widespread solution for such problems in the industry
is to use code generation.
I’m generally skeptical of code generation of this sort,
which usually means passing the buck to some other half baked scripts.
These scripts would be in a different language,
so they would require us to either spin off or duplicate information we need in SystemVerilog.
They also wouldn’t integrate as well into the overall development and execution flow.</p>

<p>We’ll look at an alternative way of defining tests,
which doesn’t suffer from the problems of the “traditional” approaches.
We won’t just look at the finished code,
but take a journey through the steps required to build it.</p>

<p>Before we begin,
let’s do a crash course in how UVM starts tests.
UVM uses the value of <code class="language-plaintext highlighter-rouge">+UVM_TESTNAME</code> as a type name
when it instructs the factory to create the test.
Conceptually, it does the following:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">string</span> <span class="n">test_type_name</span> <span class="o">=</span> <span class="n">get_value_of_plusarg</span><span class="p">(</span><span class="s">"UVM_TESTNAME"</span><span class="p">);</span>
<span class="n">uvm_component</span> <span class="n">test</span> <span class="o">=</span> <span class="n">uvm_factory</span><span class="p">()</span><span class="o">::</span><span class="n">get</span><span class="p">().</span><span class="n">create_component_by_name</span><span class="p">(</span><span class="n">test_type_name</span><span class="p">);</span>
</code></pre></div></div>

<p>Users define their test classes
and register them with the factory using the <code class="language-plaintext highlighter-rouge">uvm_component_utils</code> macro.
This makes it possible for the test type name to be used as an argument to <code class="language-plaintext highlighter-rouge">+UVM_TESTNAME</code>.</p>

<p>To reduce the amount of code we need,
we want to consolidate the duplicated code into a single place.
If we look at the tests,
they only differ by the type of the <code class="language-plaintext highlighter-rouge">seq</code> variable,
which holds the sequence to start.
We can create a shared template
by using a class that is parameterized by the sequence type:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">class</span> <span class="n">test_that_executes_sequence_via_param</span> <span class="p">#(</span><span class="k">type</span> <span class="n">SEQ</span> <span class="o">=</span> <span class="kt">int</span><span class="p">)</span> <span class="k">extends</span> <span class="n">uvm_test</span><span class="p">;</span>

  <span class="k">function</span> <span class="k">new</span><span class="p">(</span><span class="kt">string</span> <span class="n">name</span><span class="p">,</span> <span class="n">uvm_component</span> <span class="n">parent</span><span class="p">);</span>
    <span class="k">super</span><span class="p">.</span><span class="k">new</span><span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="n">parent</span><span class="p">);</span>
  <span class="k">endfunction</span>

  <span class="kt">virtual</span> <span class="k">task</span> <span class="n">run_phase</span><span class="p">(</span><span class="n">uvm_phase</span> <span class="n">phase</span><span class="p">);</span>
    <span class="n">SEQ</span> <span class="n">seq</span> <span class="o">=</span> <span class="n">SEQ</span><span class="o">::</span><span class="n">type_id</span><span class="o">::</span><span class="n">create</span><span class="p">(</span><span class="s">"seq"</span><span class="p">,</span> <span class="k">this</span><span class="p">);</span>
    <span class="n">phase</span><span class="p">.</span><span class="n">raise_objection</span><span class="p">(</span><span class="k">this</span><span class="p">);</span>
    <span class="n">seq</span><span class="p">.</span><span class="n">start</span><span class="p">(</span><span class="k">null</span><span class="p">);</span>
    <span class="n">phase</span><span class="p">.</span><span class="n">drop_objection</span><span class="p">(</span><span class="k">this</span><span class="p">);</span>
  <span class="k">endtask</span>

  <span class="cp">`uvm_component_param_utils</span><span class="p">(</span><span class="n">test_that_executes_sequence_via_param</span> <span class="p">#(</span><span class="n">SEQ</span><span class="p">))</span>

<span class="k">endclass</span>
</code></pre></div></div>

<p>While the <code class="language-plaintext highlighter-rouge">uvm_component_param_utils</code> macro will register the class with the UVM factory,
it will not register it using a type name.
Since we don’t have type names,
we won’t have anything to pass to <code class="language-plaintext highlighter-rouge">+UVM_TESTNAME</code> to select tests.</p>

<p>We could create subclasses of the parameterized class,
where we pass the desired sequence type for the <code class="language-plaintext highlighter-rouge">SEQ</code> parameter,
and register those with the factory.
For example, for <code class="language-plaintext highlighter-rouge">some_sequence</code> we would have:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">class</span> <span class="n">test_that_executes_some_sequence_using_param</span>
    <span class="k">extends</span> <span class="n">test_that_executes_sequence_via_param</span> <span class="p">#(</span><span class="n">some_sequence</span><span class="p">);</span>

  <span class="k">function</span> <span class="k">new</span><span class="p">(</span><span class="kt">string</span> <span class="n">name</span><span class="p">,</span> <span class="n">uvm_component</span> <span class="n">parent</span><span class="p">);</span>
    <span class="k">super</span><span class="p">.</span><span class="k">new</span><span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="n">parent</span><span class="p">);</span>
  <span class="k">endfunction</span>

  <span class="cp">`uvm_component_utils</span><span class="p">(</span><span class="n">test_that_executes_some_sequence_using_param</span><span class="p">)</span>

<span class="k">endclass</span>
</code></pre></div></div>

<p>This is still a pretty large amount of boilerplate.
Granted, this is code that might not ever change.
We could do a little better, though.</p>

<p>The <code class="language-plaintext highlighter-rouge">uvm_component_utils</code> macro maps type names to “real” classes using the <code class="language-plaintext highlighter-rouge">uvm_component_registry</code> class.
If we were to expand the code for <code class="language-plaintext highlighter-rouge">uvm_component_utils(test_that_executes_some_sequence_using_param)</code>
we would see <code class="language-plaintext highlighter-rouge">uvm_component_registry #(test_that_executes_some_sequence_using_param, "test_that_executes_some_sequence_using_param")</code>.
This instructs the factory to create a component of type <code class="language-plaintext highlighter-rouge">test_that_executes_some_sequence_using_param</code>
whenever the string <code class="language-plaintext highlighter-rouge">"test_that_executes_some_sequence_using_param"</code> is supplied as a type name.</p>

<p>The exact way this is done is kind of all over the place.
The underlying class that the factory uses is called <code class="language-plaintext highlighter-rouge">uvm_object_wrapper</code>.
It declares two functions,
<code class="language-plaintext highlighter-rouge">create_object()</code> and <code class="language-plaintext highlighter-rouge">create_component()</code>,
which the factory uses to create instances.
The <code class="language-plaintext highlighter-rouge">uvm_component_registry</code> class extends <code class="language-plaintext highlighter-rouge">uvm_object_wrapper</code>
and implements its <code class="language-plaintext highlighter-rouge">create_component()</code> function,
but it also has many other functions related to registering itself with the factory and handling type overrides.
A cleaner implementation would have been for <code class="language-plaintext highlighter-rouge">uvm_component_registry</code> to be its own class,
that doesn’t extend <code class="language-plaintext highlighter-rouge">uvm_object_wrapper</code>,
that instead creates an instance of a <code class="language-plaintext highlighter-rouge">uvm_object_wrapper</code> and registers it with the factory instead of itself.
This would have provided a better separation of concerns.</p>

<p>We want to create our own mapping,
which instructs the factory to create a component of type <code class="language-plaintext highlighter-rouge">test_that_executes_sequence_via_param #(some_sequence)</code>
whenever the string <code class="language-plaintext highlighter-rouge">"test_that_executes_some_sequence_using_param"</code> is supplied as a type name.
The easiest way to do this is by creating own own class that extends <code class="language-plaintext highlighter-rouge">uvm_component_registry</code> with the appropriate parameters:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">class</span> <span class="n">wrapper_for_test_that_executes_some_sequence_using_param</span>
    <span class="k">extends</span> <span class="n">uvm_component_registry</span> <span class="p">#(</span><span class="n">test_that_executes_sequence_via_param</span> <span class="p">#(</span><span class="n">some_sequence</span><span class="p">),</span> <span class="s">"test_that_executes_some_sequence_using_param"</span><span class="p">);</span>
<span class="k">endclass</span>
</code></pre></div></div>

<p>This class just has to exist.
The code in <code class="language-plaintext highlighter-rouge">uvm_component_registry</code> will take care of instructing the UVM factory
to produce an instance of the test class parameterized with <code class="language-plaintext highlighter-rouge">some_sequence</code>
when <code class="language-plaintext highlighter-rouge">test_that_executes_some_sequence_using_param</code> is passed as a value for <code class="language-plaintext highlighter-rouge">+UVM_TESTNAME</code>.</p>

<p>While using parameterization solves a part of the boilerplate issue
by having the aspect of “starting sequences” in a single class,
it still requires us to write the wrapper classes necessary for factory registration by hand.
We can’t implement any kind of looping over the sequences we want to start from tests,
as we set out to do.</p>

<p>We have to transpose our code from using types and parameterization to some kind of dynamic constructs.
If we go back to <code class="language-plaintext highlighter-rouge">test_test_that_executes_sequence_via_param</code>,
we see that the type of sequence is not at all relevant to starting it.
All <code class="language-plaintext highlighter-rouge">uvm_sequences</code> have a <code class="language-plaintext highlighter-rouge">start()</code> task,
which can be used by the test to start it:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="kt">virtual</span> <span class="k">task</span> <span class="n">run_phase</span><span class="p">(</span><span class="n">uvm_phase</span> <span class="n">phase</span><span class="p">);</span>
    <span class="n">uvm_sequence</span> <span class="n">seq</span> <span class="o">=</span> <span class="n">create_seq</span><span class="p">();</span>
    <span class="n">phase</span><span class="p">.</span><span class="n">raise_objection</span><span class="p">(</span><span class="k">this</span><span class="p">);</span>
    <span class="n">seq</span><span class="p">.</span><span class="n">start</span><span class="p">(</span><span class="k">null</span><span class="p">);</span>
    <span class="n">phase</span><span class="p">.</span><span class="n">drop_objection</span><span class="p">(</span><span class="k">this</span><span class="p">);</span>
  <span class="k">endtask</span>
</code></pre></div></div>

<p>We just need a way of creating sequences without hard-coding the exact type.
Luckily, the UVM factory already has us covered here.
Remember that <code class="language-plaintext highlighter-rouge">uvm_object_utils</code> creates a subclass of <code class="language-plaintext highlighter-rouge">uvm_object_wrapper</code> that can create the “real” type:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">uvm_sequence</span> <span class="n">seq</span><span class="p">;</span>
<span class="n">uvm_object_wrapper</span> <span class="n">seq_wrapper</span> <span class="o">=</span> <span class="n">some_sequence</span><span class="o">::</span><span class="n">get_type</span><span class="p">()</span>
<span class="p">$</span><span class="nb">cast</span><span class="p">(</span><span class="n">result</span><span class="p">,</span> <span class="n">seq_wrapper</span><span class="p">.</span><span class="n">create_object</span><span class="p">(</span><span class="s">"seq"</span><span class="p">));</span>
</code></pre></div></div>

<p>Instead of hard coding the sequence type in the test,
so the test can create an instance of that sequence itself,
we can instead supply it with a <code class="language-plaintext highlighter-rouge">uvm_object_wrapper</code> that produces that sequence:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">class</span> <span class="n">test_that_executes_sequence_via_constructor</span> <span class="k">extends</span> <span class="n">uvm_test</span><span class="p">;</span>

  <span class="k">local</span> <span class="kt">const</span> <span class="n">uvm_object_wrapper</span> <span class="n">seq_wrapper</span><span class="p">;</span>

  <span class="k">function</span> <span class="k">new</span><span class="p">(</span><span class="kt">string</span> <span class="n">name</span><span class="p">,</span> <span class="n">uvm_component</span> <span class="n">parent</span><span class="p">,</span> <span class="n">uvm_object_wrapper</span> <span class="n">seq_wrapper</span><span class="p">);</span>
    <span class="k">super</span><span class="p">.</span><span class="k">new</span><span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="n">parent</span><span class="p">);</span>
    <span class="k">this</span><span class="p">.</span><span class="n">seq_wrapper</span> <span class="o">=</span> <span class="n">seq_wrapper</span><span class="p">;</span>
  <span class="k">endfunction</span>

  <span class="kt">virtual</span> <span class="k">task</span> <span class="n">run_phase</span><span class="p">(</span><span class="n">uvm_phase</span> <span class="n">phase</span><span class="p">);</span>
    <span class="n">uvm_sequence</span> <span class="n">seq</span> <span class="o">=</span> <span class="n">create_seq</span><span class="p">();</span>
    <span class="n">phase</span><span class="p">.</span><span class="n">raise_objection</span><span class="p">(</span><span class="k">this</span><span class="p">);</span>
    <span class="n">seq</span><span class="p">.</span><span class="n">start</span><span class="p">(</span><span class="k">null</span><span class="p">);</span>
    <span class="n">phase</span><span class="p">.</span><span class="n">drop_objection</span><span class="p">(</span><span class="k">this</span><span class="p">);</span>
  <span class="k">endtask</span>

  <span class="k">local</span> <span class="k">function</span> <span class="n">uvm_sequence</span> <span class="n">create_seq</span><span class="p">();</span>
    <span class="n">uvm_sequence</span> <span class="n">result</span><span class="p">;</span>
    <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="p">$</span><span class="nb">cast</span><span class="p">(</span><span class="n">result</span><span class="p">,</span> <span class="n">seq_wrapper</span><span class="p">.</span><span class="n">create_object</span><span class="p">(</span><span class="s">"seq"</span><span class="p">)))</span>
      <span class="cp">`uvm_fatal</span><span class="p">(</span><span class="s">"TEST"</span><span class="p">,</span> <span class="s">"Cannot construct sequence from supplied wrapper"</span><span class="p">)</span>
    <span class="k">return</span> <span class="n">result</span><span class="p">;</span>
  <span class="k">endfunction</span>

<span class="k">endclass</span>
</code></pre></div></div>

<p>Notice that we have to check at run time
whether the <code class="language-plaintext highlighter-rouge">seq_wrapper</code> we got can really produce an object of type <code class="language-plaintext highlighter-rouge">uvm_sequence</code>.
In other programming languages,
which take class parameterization seriously and where it’s not just an afterthought,
it is possible to enforce this compile time.
This would be done by declaring the <code class="language-plaintext highlighter-rouge">seq_wrapper</code> argument as being a <code class="language-plaintext highlighter-rouge">uvm_object_wrapper</code> of a type that extends <code class="language-plaintext highlighter-rouge">uvm_sequence</code>.
The syntax could look something like the following:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">function</span> <span class="k">new</span><span class="p">(</span><span class="n">uvm_object_wrapper</span> <span class="p">#(</span><span class="o">?</span> <span class="k">extends</span> <span class="n">uvm_sequence</span><span class="p">)</span> <span class="n">seq_wrapper</span><span class="p">)</span>
</code></pre></div></div>

<p>For reference, in Java this language feature is called an <a href="https://docs.oracle.com/javase/tutorial/java/generics/upperBounded.html">upper bounded wildcard</a>.</p>

<p>The tricky part is figuring out how to supply the sequence wrapper.
We’ve already talked about how the factory uses <code class="language-plaintext highlighter-rouge">uvm_object_wrappers</code> to perform the actual creation
and maps type names to such objects.</p>

<p>Let’s look at how we would create a <code class="language-plaintext highlighter-rouge">uvm_object_wrapper</code>
that creates a test that starts <code class="language-plaintext highlighter-rouge">some_sequence</code>
and registers itself with the name <code class="language-plaintext highlighter-rouge">"test_that_executes_some_sequence_using_constructor"</code>.
The first thing we need to implement is the <code class="language-plaintext highlighter-rouge">create_component()</code> function:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">class</span> <span class="n">wrapper_for_test_that_executes_some_sequence_using_constructor</span>
    <span class="k">extends</span> <span class="n">uvm_object_wrapper</span><span class="p">;</span>

  <span class="kt">virtual</span> <span class="k">function</span> <span class="n">uvm_component</span> <span class="n">create_component</span><span class="p">(</span><span class="kt">string</span> <span class="n">name</span><span class="p">,</span> <span class="n">uvm_component</span> <span class="n">parent</span><span class="p">);</span>
    <span class="n">test_that_executes_sequence_via_constructor</span> <span class="n">result</span> <span class="o">=</span> <span class="k">new</span><span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="n">parent</span><span class="p">,</span> <span class="n">some_sequence</span><span class="o">::</span><span class="n">get_type</span><span class="p">());</span>
    <span class="k">return</span> <span class="n">result</span><span class="p">;</span>
  <span class="k">endfunction</span>

<span class="k">endclass</span>
</code></pre></div></div>

<p>The <code class="language-plaintext highlighter-rouge">uvm_object_wrapper</code> class also provides a <code class="language-plaintext highlighter-rouge">get_type_name()</code> function,
which is supposed to return the name of type being wrapped.
I noticed that if we don’t implement this function,
we get some annoying prints in the console,
so let’s do this as well:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">class</span> <span class="n">wrapper_for_test_that_executes_some_sequence_using_constructor</span>
    <span class="k">extends</span> <span class="n">uvm_object_wrapper</span><span class="p">;</span>

  <span class="kt">virtual</span> <span class="k">function</span> <span class="kt">string</span> <span class="n">get_type_name</span><span class="p">();</span>
    <span class="k">return</span> <span class="s">"test_that_executes_some_sequence_using_constructor"</span><span class="p">;</span>
  <span class="k">endfunction</span>

  <span class="c1">// ...</span>

<span class="k">endclass</span>
</code></pre></div></div>

<p>Last, but not least,
we should also register this wrapper with the UVM factory,
so it knows how to produce instances when <code class="language-plaintext highlighter-rouge">"test_that_executes_some_sequence_using_constructor"</code> is used as a type name.
This is more or less a copy/paste of how <code class="language-plaintext highlighter-rouge">uvm_component_registry</code> does it:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">class</span> <span class="n">wrapper_for_test_that_executes_some_sequence_using_constructor</span>
    <span class="k">extends</span> <span class="n">uvm_object_wrapper</span><span class="p">;</span>

  <span class="k">local</span> <span class="kt">static</span> <span class="n">wrapper_for_test_that_executes_some_sequence_using_constructor</span> <span class="n">me</span> <span class="o">=</span> <span class="n">get</span><span class="p">();</span>

  <span class="k">local</span> <span class="k">function</span> <span class="k">new</span><span class="p">();</span>
  <span class="k">endfunction</span>

  <span class="kt">static</span> <span class="k">function</span> <span class="n">wrapper_for_test_that_executes_some_sequence_using_constructor</span> <span class="n">get</span><span class="p">();</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">me</span> <span class="o">==</span> <span class="k">null</span><span class="p">)</span> <span class="k">begin</span>
  	  <span class="n">uvm_coreservice_t</span> <span class="n">cs</span> <span class="o">=</span> <span class="n">uvm_coreservice_t</span><span class="o">::</span><span class="n">get</span><span class="p">();</span>
  	  <span class="n">uvm_factory</span> <span class="n">factory</span> <span class="o">=</span> <span class="n">cs</span><span class="p">.</span><span class="n">get_factory</span><span class="p">();</span>
      <span class="n">me</span> <span class="o">=</span> <span class="k">new</span><span class="p">();</span>
      <span class="n">factory</span><span class="p">.</span><span class="n">register</span><span class="p">(</span><span class="n">me</span><span class="p">);</span>
    <span class="k">end</span>
    <span class="k">return</span> <span class="n">me</span><span class="p">;</span>
  <span class="k">endfunction</span>

  <span class="c1">// ...</span>

<span class="k">endclass</span>
</code></pre></div></div>

<p>It’s worth discussing about how registration is actually triggered.
Notice that the <code class="language-plaintext highlighter-rouge">me</code> variable is static,
but has a initial value.
This value is computed during static initialization,
which happens very early within a simulation,
before any processes (e.g. from <code class="language-plaintext highlighter-rouge">initial</code> or <code class="language-plaintext highlighter-rouge">always</code> blocks) are executed.</p>

<p>If we were to have to write a <code class="language-plaintext highlighter-rouge">uvm_object_wrapper</code> for each of the sequences we want to start,
we’d end up with a lot of boilerplate.
This is exactly what we want to avoid.</p>

<p>We notice that we can pass the sequence wrapper as an argument to the test wrapper itself:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">class</span> <span class="n">wrapper_for_test_that_executes_sequence_using_constructor</span>
    <span class="k">extends</span> <span class="n">uvm_object_wrapper</span><span class="p">;</span>

  <span class="k">local</span> <span class="kt">const</span> <span class="n">uvm_object_wrapper</span> <span class="n">seq_wrapper</span><span class="p">;</span>

  <span class="k">function</span> <span class="k">new</span><span class="p">(</span><span class="n">uvm_object_wrapper</span> <span class="n">seq_wrapper</span><span class="p">);</span>
    <span class="k">this</span><span class="p">.</span><span class="n">seq_wrapper</span> <span class="o">=</span> <span class="n">seq_wrapper</span><span class="p">;</span>
  <span class="k">endfunction</span>

  <span class="kt">virtual</span> <span class="k">function</span> <span class="kt">string</span> <span class="n">get_type_name</span><span class="p">();</span>
    <span class="k">return</span> <span class="p">$</span><span class="nb">sformatf</span><span class="p">(</span><span class="s">"test_that_executes_%s_using_constructor"</span><span class="p">,</span> <span class="n">seq_wrapper</span><span class="p">.</span><span class="n">get_type_name</span><span class="p">());</span>
  <span class="k">endfunction</span>

  <span class="kt">virtual</span> <span class="k">function</span> <span class="n">uvm_component</span> <span class="n">create_component</span><span class="p">(</span><span class="kt">string</span> <span class="n">name</span><span class="p">,</span> <span class="n">uvm_component</span> <span class="n">parent</span><span class="p">);</span>
    <span class="n">test_that_executes_sequence_via_constructor</span> <span class="n">result</span> <span class="o">=</span> <span class="k">new</span><span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="n">parent</span><span class="p">,</span> <span class="n">seq_wrapper</span><span class="p">);</span>
    <span class="k">return</span> <span class="n">result</span><span class="p">;</span>
  <span class="k">endfunction</span>

<span class="k">endclass</span>
</code></pre></div></div>

<p>We can extract the code for factory registration to a different class,
which is responsible for registering tests for the sequences we want to start:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">class</span> <span class="n">tests_that_execute_each_sequence</span><span class="p">;</span>

  <span class="k">local</span> <span class="kt">static</span> <span class="kt">bit</span> <span class="n">test_for_some_other_sequence_registered</span> <span class="o">=</span> <span class="n">register_test</span><span class="p">(</span><span class="n">some_other_sequence</span><span class="o">::</span><span class="n">get_type</span><span class="p">());</span>
  <span class="k">local</span> <span class="kt">static</span> <span class="kt">bit</span> <span class="n">test_for_yet_another_sequence_registered</span> <span class="o">=</span> <span class="n">register_test</span><span class="p">(</span><span class="n">yet_another_sequence</span><span class="o">::</span><span class="n">get_type</span><span class="p">());</span>

  <span class="k">local</span> <span class="kt">static</span> <span class="k">function</span> <span class="kt">bit</span> <span class="n">register_test</span><span class="p">(</span><span class="n">uvm_object_wrapper</span> <span class="n">seq_wrapper</span><span class="p">);</span>
    <span class="n">uvm_coreservice_t</span> <span class="n">cs</span> <span class="o">=</span> <span class="n">uvm_coreservice_t</span><span class="o">::</span><span class="n">get</span><span class="p">();</span>
  	<span class="n">uvm_factory</span> <span class="n">factory</span> <span class="o">=</span> <span class="n">cs</span><span class="p">.</span><span class="n">get_factory</span><span class="p">();</span>
    <span class="n">wrapper_for_test_that_executes_sequence_using_constructor</span> <span class="n">test_wrapper</span> <span class="o">=</span> <span class="k">new</span><span class="p">(</span><span class="n">seq_wrapper</span><span class="p">);</span>
    <span class="n">factory</span><span class="p">.</span><span class="n">register</span><span class="p">(</span><span class="n">test_wrapper</span><span class="p">);</span>
    <span class="k">return</span> <span class="mi">1</span><span class="p">;</span>
  <span class="k">endfunction</span>

<span class="k">endclass</span>
</code></pre></div></div>

<p>Notice that the <code class="language-plaintext highlighter-rouge">register_test()</code> function returns a <code class="language-plaintext highlighter-rouge">bit</code>,
but the value is always <code class="language-plaintext highlighter-rouge">1</code>.
This is so that it can be used as an initial value for a static helper variable,
so that the function is called during static initialization.</p>

<p>The <code class="language-plaintext highlighter-rouge">tests_that_execute_each_sequence</code> class does a bit much, though.
It knows how to register tests with the factory, but is also registers the tests we want.</p>

<p>We can extract the code for registration into an own class:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">class</span> <span class="n">test_builder</span><span class="p">;</span>

  <span class="k">local</span> <span class="kt">const</span> <span class="n">wrapper_for_test_that_executes_sequence_using_constructor</span> <span class="n">test_wrapper</span><span class="p">;</span>

  <span class="k">local</span> <span class="k">function</span> <span class="k">new</span><span class="p">(</span><span class="n">uvm_object_wrapper</span> <span class="n">seq_wrapper</span><span class="p">);</span>
    <span class="n">test_wrapper</span> <span class="o">=</span> <span class="k">new</span><span class="p">(</span><span class="n">seq_wrapper</span><span class="p">);</span>
  <span class="k">endfunction</span>

  <span class="kt">static</span> <span class="k">function</span> <span class="n">test_builder</span> <span class="n">for_sequence_type</span><span class="p">(</span><span class="n">uvm_object_wrapper</span> <span class="n">seq_wrapper</span><span class="p">);</span>
    <span class="n">test_builder</span> <span class="n">result</span> <span class="o">=</span> <span class="k">new</span><span class="p">(</span><span class="n">seq_wrapper</span><span class="p">);</span>
    <span class="k">return</span> <span class="n">result</span><span class="p">;</span>
  <span class="k">endfunction</span>

  <span class="k">function</span> <span class="kt">bit</span> <span class="n">register</span><span class="p">();</span>
    <span class="n">uvm_coreservice_t</span> <span class="n">cs</span> <span class="o">=</span> <span class="n">uvm_coreservice_t</span><span class="o">::</span><span class="n">get</span><span class="p">();</span>
  	<span class="n">uvm_factory</span> <span class="n">factory</span> <span class="o">=</span> <span class="n">cs</span><span class="p">.</span><span class="n">get_factory</span><span class="p">();</span>
    <span class="n">factory</span><span class="p">.</span><span class="n">register</span><span class="p">(</span><span class="n">test_wrapper</span><span class="p">);</span>
    <span class="k">return</span> <span class="mi">1</span><span class="p">;</span>
  <span class="k">endfunction</span>

<span class="k">endclass</span>
</code></pre></div></div>

<p>Registering tests for the sequences is a bit cleaner,
because we’re not distracted by the actual test builder code.</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">class</span> <span class="n">tests_that_execute_each_sequence</span><span class="p">;</span>

  <span class="k">local</span> <span class="kt">static</span> <span class="kt">bit</span> <span class="n">test_for_some_other_sequence_registered</span>
      <span class="o">=</span> <span class="n">test_builder</span><span class="o">::</span><span class="n">for_sequence_type</span><span class="p">(</span><span class="n">some_other_sequence</span><span class="o">::</span><span class="n">get_type</span><span class="p">()).</span><span class="n">register</span><span class="p">();</span>
  <span class="k">local</span> <span class="kt">static</span> <span class="kt">bit</span> <span class="n">test_for_yet_another_sequence_registered</span>
      <span class="o">=</span> <span class="n">test_builder</span><span class="o">::</span><span class="n">for_sequence_type</span><span class="p">(</span><span class="n">yet_another_sequence</span><span class="o">::</span><span class="n">get_type</span><span class="p">()).</span><span class="n">register</span><span class="p">();</span>

<span class="k">endclass</span>
</code></pre></div></div>

<p>Now it starts to become obvious that we can use a loop to register the tests:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">class</span> <span class="n">tests_that_execute_each_sequence</span><span class="p">;</span>

  <span class="k">local</span> <span class="kt">static</span> <span class="kt">bit</span> <span class="n">tests_registered</span> <span class="o">=</span> <span class="n">register_tests</span><span class="p">();</span>

  <span class="k">local</span> <span class="kt">static</span> <span class="k">function</span> <span class="kt">bit</span> <span class="n">register_tests</span><span class="p">();</span>
    <span class="n">uvm_object_wrapper</span> <span class="n">seqs</span><span class="p">[]</span> <span class="o">=</span> <span class="err">'</span><span class="o">{</span>
        <span class="n">some_sequence</span><span class="o">::</span><span class="n">get_type</span><span class="p">(),</span>
        <span class="n">some_other_sequence</span><span class="o">::</span><span class="n">get_type</span><span class="p">(),</span>
        <span class="n">yet_another_sequence</span><span class="o">::</span><span class="n">get_type</span><span class="p">()</span> <span class="o">}</span><span class="p">;</span>

    <span class="k">foreach</span> <span class="p">(</span><span class="n">seqs</span><span class="p">[</span><span class="n">i</span><span class="p">])</span>
      <span class="kt">void</span><span class="err">'</span><span class="p">(</span><span class="n">test_builder</span><span class="o">::</span><span class="n">for_sequence_type</span><span class="p">(</span><span class="n">seqs</span><span class="p">[</span><span class="n">i</span><span class="p">]).</span><span class="n">register</span><span class="p">());</span>
  <span class="k">endfunction</span>

<span class="k">endclass</span>
</code></pre></div></div>

<p>While it’s very convenient to use loops,
being able to use procedural code to define tests is extremely powerful.
It makes it possible to do things like
to conditionally define tests based on conditions known to the testbench (for example, whether a feature is present in the DUT)
or to read some input file and define tests based on that.
The space of possibilities is huge.</p>

<p>To reap the benefits of dynamic test creation,
we would want to integrate the code from above into our own projects.
The <code class="language-plaintext highlighter-rouge">test_builder</code> class and its associated classes feel as if they shouldn’t depend on any kind of user code
and that they could be reusable.</p>

<p>One thing a <code class="language-plaintext highlighter-rouge">uvm_test</code> also does,
that we completely left out of the examples,
is to instantiate the rest of the verification environment (i.e. the agents, scoreboards, etc.).
The examples we’ve looked at so far completely ignore this fact.
We’ll emulate it with an info message in the build phase:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">virtual</span> <span class="kt">class</span> <span class="n">abstract_test</span> <span class="k">extends</span> <span class="n">uvm_test</span><span class="p">;</span>

  <span class="k">function</span> <span class="k">new</span><span class="p">(</span><span class="kt">string</span> <span class="n">name</span><span class="p">,</span> <span class="n">uvm_component</span> <span class="n">parent</span><span class="p">);</span>
    <span class="k">super</span><span class="p">.</span><span class="k">new</span><span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="n">parent</span><span class="p">);</span>
  <span class="k">endfunction</span>

  <span class="kt">virtual</span> <span class="k">function</span> <span class="kt">void</span> <span class="n">build_phase</span><span class="p">(</span><span class="n">uvm_phase</span> <span class="n">phase</span><span class="p">);</span>
    <span class="k">super</span><span class="p">.</span><span class="n">build_phase</span><span class="p">(</span><span class="n">phase</span><span class="p">);</span>
    <span class="cp">`uvm_info</span><span class="p">(</span><span class="s">"TEST"</span><span class="p">,</span> <span class="s">"Building TB..."</span><span class="p">,</span> <span class="n">UVM_NONE</span><span class="p">)</span>
  <span class="k">endfunction</span>

<span class="k">endclass</span>
</code></pre></div></div>

<p>The <code class="language-plaintext highlighter-rouge">test_builder</code> registers tests of the type <code class="language-plaintext highlighter-rouge">test_that_executes_sequence</code>,
which only knows how to start sequences,
but knows nothing about TB creation.
In order to combine the two,
<code class="language-plaintext highlighter-rouge">test_that_executes_sequence</code> can become a <a href="https://en.wikipedia.org/wiki/Mixin">mixin</a>,
allowing the user to include it onto their <code class="language-plaintext highlighter-rouge">abstract_test</code> class:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">class</span> <span class="n">test_that_executes_sequence</span> <span class="p">#(</span><span class="k">type</span> <span class="n">T</span> <span class="o">=</span> <span class="n">uvm_test</span><span class="p">)</span> <span class="k">extends</span> <span class="n">T</span><span class="p">;</span>

    <span class="c1">// ...</span>

<span class="k">endclass</span>
</code></pre></div></div>

<p>Naturally, the parameter has to propagate to the other classes as well:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">class</span> <span class="n">wrapper_for_test_that_executes_sequence</span> <span class="p">#(</span><span class="k">type</span> <span class="n">T</span> <span class="o">=</span> <span class="n">uvm_test</span><span class="p">)</span> <span class="k">extends</span> <span class="n">uvm_object_wrapper</span><span class="p">;</span>

  <span class="kt">virtual</span> <span class="k">function</span> <span class="n">uvm_component</span> <span class="n">create_component</span><span class="p">(</span><span class="kt">string</span> <span class="n">name</span><span class="p">,</span> <span class="n">uvm_component</span> <span class="n">parent</span><span class="p">);</span>
    <span class="n">test_that_executes_sequence</span> <span class="p">#(</span><span class="n">T</span><span class="p">)</span> <span class="n">result</span> <span class="o">=</span> <span class="k">new</span><span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="n">parent</span><span class="p">,</span> <span class="n">seq_wrapper</span><span class="p">);</span>
    <span class="k">return</span> <span class="n">result</span><span class="p">;</span>
  <span class="k">endfunction</span>

  <span class="c1">// ...</span>

<span class="k">endclass</span>
</code></pre></div></div>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">class</span> <span class="n">test_builder</span> <span class="p">#(</span><span class="k">type</span> <span class="n">T</span> <span class="o">=</span> <span class="n">uvm_test</span><span class="p">);</span>

  <span class="k">local</span> <span class="kt">const</span> <span class="n">wrapper_for_test_that_executes_sequence</span> <span class="p">#(</span><span class="n">T</span><span class="p">)</span> <span class="n">test_wrapper</span><span class="p">;</span>

  <span class="kt">static</span> <span class="k">function</span> <span class="n">test_builder</span> <span class="p">#(</span><span class="n">T</span><span class="p">)</span> <span class="n">for_sequence_type</span><span class="p">(</span><span class="n">uvm_object_wrapper</span> <span class="n">seq_wrapper</span><span class="p">);</span>
    <span class="n">test_builder</span> <span class="p">#(</span><span class="n">T</span><span class="p">)</span> <span class="n">result</span> <span class="o">=</span> <span class="k">new</span><span class="p">(</span><span class="n">seq_wrapper</span><span class="p">);</span>
    <span class="k">return</span> <span class="n">result</span><span class="p">;</span>
  <span class="k">endfunction</span>

  <span class="c1">// ...</span>

<span class="k">endclass</span>
</code></pre></div></div>

<p>This allows users to layer test building onto their own code:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">class</span> <span class="n">tests_that_execute_each_sequence</span><span class="p">;</span>

  <span class="k">local</span> <span class="kt">static</span> <span class="k">function</span> <span class="kt">bit</span> <span class="n">register_tests</span><span class="p">();</span>
    <span class="c1">// ...</span>
    <span class="k">foreach</span> <span class="p">(</span><span class="n">seqs</span><span class="p">[</span><span class="n">i</span><span class="p">])</span>
      <span class="kt">void</span><span class="err">'</span><span class="p">(</span><span class="n">test_builder</span> <span class="p">#(</span><span class="n">abstract_test</span><span class="p">)</span><span class="o">::</span><span class="n">for_sequence_type</span><span class="p">(</span><span class="n">seqs</span><span class="p">[</span><span class="n">i</span><span class="p">]).</span><span class="n">register</span><span class="p">());</span>
  <span class="k">endfunction</span>

  <span class="c1">// ...</span>

<span class="k">endclass</span>
</code></pre></div></div>

<p>At the moment, I see the test builder as more of a pattern, instead of a reusable library,
because there’s not much code there to reuse directly.
A full example can be found at <a href="https://github.com/verification-gentleman-blog/creating-uvm-tests-dynamically">https://github.com/verification-gentleman-blog/creating-uvm-tests-dynamically</a>.
It can serve as the basis for implementing the pattern in your own projects.</p>

<p>In a future post,
I’m going to show you how to use dynamic test creation to layer constraints onto a random test,
in order to target certain areas of the design space.
Be sure to subscribe if you don’t want to miss it.</p>]]></content><author><name>Tudor Timi</name></author><category term="SystemVerilog" /><category term="UVM" /><summary type="html"><![CDATA[Everyone who uses UVM knows that using the library ofter requires large amounts of boilerplate code. Tests are no exception.]]></summary></entry><entry><title type="html">Goodbye Blogger, Hello Static Site</title><link href="https://blog.verificationgentleman.com/2021/11/14/goodbye-blogger-hello-static-site.html" rel="alternate" type="text/html" title="Goodbye Blogger, Hello Static Site" /><published>2021-11-14T18:32:00+01:00</published><updated>2021-11-14T18:32:00+01:00</updated><id>https://blog.verificationgentleman.com/2021/11/14/goodbye-blogger-hello-static-site</id><content type="html" xml:base="https://blog.verificationgentleman.com/2021/11/14/goodbye-blogger-hello-static-site.html"><![CDATA[<h2 id="announcement">Announcement</h2>

<p>The Verification Gentleman Blog will be moving from Blogger.</p>

<h2 id="why">Why?</h2>

<p>While Blogger was a great platform to start on, especially considering the fact that it’s 100% free, I feel that I’ve outgrown it.</p>

<p>The interface is very arcane and it’s very difficult to do any kind of customization. For example, setting up syntax highlighting required fiddling with a lot of things to get it working and even then the results aren’t all that great. It’s very easy to mess up the entire blog and not be able to restore it to a previous version.</p>

<p>Writing posts requires too much manual intervention. It all went downhill when Windows Live Writer stopped working, which meant that edits had to be done in the web interface. I spent quite some time setting up a flow to generate the HTML for Blogger using <a href="https://blog.getpelican.com/">Pelican</a>, but this still requires a lot of manual steps. Since previews have to be done from the web interface, any kind of change requires an update of the post’s source, generation of the HTML, copy/pasting the HTML into the Blogger web interface and re-inspecting the preview. This is very time consuming and draining. Working with images or any other kinds of external content is also a pain.</p>

<p>Blogger currently only supports comments from Google users. It used to support more authentication sources, but apparently these got dropped a while ago. Coupled with the fact that a lot of people have deleted their Google accounts, a lot of comments ended up as being posted by “Unknown” or “Anonymous”.</p>

<p>Incidentally, I thought I’d write this post in the Blogger web interface directly, to save time. While working on it, Blogger was nice enough to throw out all of my content and I had to start from scratch.</p>

<h2 id="what-does-this-mean-for-readers">What does this mean for readers?</h2>

<p>I have started to migrate the blog’s content to <a href="https://jekyllrb.com/">Jekyll</a>, a static site generator. The blog’s appearance will change, but the URL will stay the same. I’ll try to keep any of the existing links working, but I might miss a few. If this is the case, please let me know so I can fix them. The current Blogger-based blog will still be available at <a href="https://verificationgentleman.blogspot.com">https://verificationgentleman.blogspot.com</a> for a while, though I do plan to eventually take it down.</p>

<p>The main thing that will change for readers is the handling of comments. I didn’t want to use a third party service, like <a href="https://disqus.com/">Disqus</a>, because these would require users to create new accounts with them in order to post. They also usually serve ads, sometimes very questionable ones I hear. I settled on <a href="https://www.discourse.org/">Discourse</a>, because it integrates very well with static sites. If you want to post comments, you’ll have to register at <a href="https://discourse.verificationgentleman.com/">https://discourse.verificationgentleman.com/</a>. The cool thing about Discourse is that it supports <a href="https://en.wikipedia.org/wiki/OAuth">OAuth</a>, so if you don’t want to sign up using an email and a password, you can use your Google, Facebook or GitHub account.</p>

<p>I’ve migrated all existing comments to Discourse. I’ve created dummy accounts for all comment authors. The user names for these account have a “_ifb” suffix (which stands for “imported from Blogger” - this had to be short, because Discourse only supports a maximum length of 20 characters). The names also contain “(Imported from Blogger)”. If you create an account and want your old comments assigned to you, you can drop me a private message and we can make it happen.</p>

<p>I still have to sort out the RSS feed, but this should be a minor issue. Email subscriptions have already stopped working, because FeedBurner killed support for them this summer. I’ll look into getting this working again, but it’s not that easy to find free services for this.</p>

<p>I also don’t have a replacement for the contact form at the moment. A private message on Discourse should be an acceptable alternative for the time being.</p>

<h2 id="closing">Closing</h2>

<p>Static site generators are much easier to work with, requiring fewer manual steps. Hopefully I’ll have to spend less time managing the blog and more time writing content for it.</p>]]></content><author><name>Tudor Timi</name></author><summary type="html"><![CDATA[Announcement]]></summary></entry><entry><title type="html">A Comparison of Formal and Simulation for a Simple, Yet Non-Trivial Design - Part 1</title><link href="https://blog.verificationgentleman.com/2020/11/25/comparison-of-formal-and-simulation-part-1.html" rel="alternate" type="text/html" title="A Comparison of Formal and Simulation for a Simple, Yet Non-Trivial Design - Part 1" /><published>2020-11-25T00:11:00+01:00</published><updated>2020-11-25T00:11:00+01:00</updated><id>https://blog.verificationgentleman.com/2020/11/25/comparison-of-formal-and-simulation-part-1</id><content type="html" xml:base="https://blog.verificationgentleman.com/2020/11/25/comparison-of-formal-and-simulation-part-1.html"><![CDATA[<p>I’ve talked a lot about constrained random verification on the blog, but now it’s time to branch out to formal verification. As a fun first post on the topic, I thought we could do a comparative study. We can take a design and write two verification environments for it, one using formal verification and the other using simulation, based on UVM. Once we’re done, it should be very interesting to be able to look at them side-by-side and to do an analysis.</p>

<p>I thought long and hard about which one of the verification environments should come first. While it might have made more sense to start with simulation, as this is what is probably most familiar to many of you, excitement got the better of me and I decided to go with formal verification.</p>

<h2 id="description-of-the-design-under-test">Description of the Design Under Test</h2>

<p>Let’s have a look at the design we’ll be verifying. My goal was to keep the design as simple as possible, so that it doesn’t require a lot of effort to understand, but for it to have a few interesting quirks that make verifying it (especially using simulation) a bit more complicated.</p>

<p>Our design under test (DUT) will be a device that can process shapes by performing various operations on them. It can process circles, rectangles and triangles. As operations, it can compute the perimeter or the area of the shape. For rectangles, it can also figure out if a given one is a square. We can only perform this query on a rectangle, though, so it won’t be possible to ask, for example, whether a circle is a square. It can also figure out whether a triangle is equilateral or whether it is isosceles. As before, these queries can only be performed on triangles.</p>

<p>Our design will have a single special function register (SFR), called <code class="language-plaintext highlighter-rouge">CTRL</code>. The <code class="language-plaintext highlighter-rouge">CTRL</code> register will be used to configure the type of shape to process and the operation to perform on it. It will have the following layout:</p>

<p><img src="https://1.bp.blogspot.com/-vpapQ4w07cc/X72Rj_hZifI/AAAAAAAAAqE/jzaTdAQ7IXYWfieWcq0GxPTfCurpbDobACPcBGAYYCw/s320/ctrl-sfr.png" alt="CTRL register layout generated using https://github.com/wavedrom/bitfield" /></p>

<p>The contents of the <code class="language-plaintext highlighter-rouge">SHAPE</code> field are one-hot encoded:</p>

<table>
  <thead>
    <tr>
      <th>Value</th>
      <th>Shape</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>‘b001</td>
      <td>CIRCLE</td>
    </tr>
    <tr>
      <td>‘b010</td>
      <td>RECTANGLE</td>
    </tr>
    <tr>
      <td>‘b100</td>
      <td>TRIANGLE</td>
    </tr>
  </tbody>
</table>

<p>The coding of the <code class="language-plaintext highlighter-rouge">OPERATION</code> field is a bit more complicated:</p>

<table>
  <thead>
    <tr>
      <th>Value</th>
      <th>Operation</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>‘b000_0000</td>
      <td>PERIMETER</td>
    </tr>
    <tr>
      <td>‘b000_0001</td>
      <td>AREA</td>
    </tr>
    <tr>
      <td>‘b010_0000</td>
      <td>IS_SQUARE</td>
    </tr>
    <tr>
      <td>‘b100_0000</td>
      <td>IS_EQUILATERAL</td>
    </tr>
    <tr>
      <td>‘b100_0001</td>
      <td>IS_ISOSCELES</td>
    </tr>
  </tbody>
</table>

<p>The uppermost three bits define which shapes can be combined with the operation. Operations that contain <code class="language-plaintext highlighter-rouge">000</code> in these bits can be used with any shape. In all other cases, these bits will contain the code for the shape on which the operation can be performed.</p>

<p>Writing a reserved value for any of the fields will cause the write to be ignored, in which case the SFR will keep its value. Writing an illegal combination of <code class="language-plaintext highlighter-rouge">SHAPE</code> and <code class="language-plaintext highlighter-rouge">OPERATION</code> values will also cause the write to be ignored.</p>

<p>To make things more interesting, the DUT provides a way of changing the operation without changing the shape. This is done by writing the special value <code class="language-plaintext highlighter-rouge">111</code> to the <code class="language-plaintext highlighter-rouge">SHAPE</code> field, together with the new value of <code class="language-plaintext highlighter-rouge">OPERATION</code>. We’ll call this special value <code class="language-plaintext highlighter-rouge">KEEP_SHAPE</code>. Having this mechanism makes it easier for software to only update the <code class="language-plaintext highlighter-rouge">OPERATION</code> field, without having to do a read-modify-write of the <code class="language-plaintext highlighter-rouge">CTRL</code> register. The resulting value of the SFR after this write operation has to contain a legal combination, otherwise the write will be ignored. For example, it is allowed to write <code class="language-plaintext highlighter-rouge">KEEP_SHAPE</code> together with <code class="language-plaintext highlighter-rouge">IS_ISOSCELES</code> if <code class="language-plaintext highlighter-rouge">CTRL.SHAPE</code> is <code class="language-plaintext highlighter-rouge">TRIANGLE</code>, because it would result in <code class="language-plaintext highlighter-rouge">(TRIANGLE, IS_ISOCELES)</code>, which is a legal combination. A write of <code class="language-plaintext highlighter-rouge">KEEP_SHAPE</code> together with <code class="language-plaintext highlighter-rouge">IS_SQUARE</code> would be ignored in the previous situation, as this would result in <code class="language-plaintext highlighter-rouge">(TRIANGLE, IS_SQUARE)</code>, which is an illegal combination.</p>

<p>A similar mechanism exists for the <code class="language-plaintext highlighter-rouge">OPERATION</code> field, where the special value <code class="language-plaintext highlighter-rouge">111_1111</code>, called <code class="language-plaintext highlighter-rouge">KEEP_OPERATION</code>, behaves like <code class="language-plaintext highlighter-rouge">KEEP_SHAPE</code>.</p>

<p>A real design would need some more SFRs to configure the shapes and to read out the results. For simplicity, we’ll skip those and focus our verification efforts on the <code class="language-plaintext highlighter-rouge">CTRL</code> register.</p>

<p>Our design will have a simple bus interface:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">module</span> <span class="n">shape_processor</span><span class="p">(</span>
    <span class="kt">input</span> <span class="kt">bit</span> <span class="n">rst_n</span><span class="p">,</span>
    <span class="kt">input</span> <span class="kt">bit</span> <span class="n">clk</span><span class="p">,</span>

    <span class="kt">input</span> <span class="kt">bit</span> <span class="nb">write</span><span class="p">,</span>
    <span class="kt">input</span> <span class="kt">bit</span> <span class="p">[</span><span class="mi">31</span><span class="o">:</span><span class="mi">0</span><span class="p">]</span> <span class="n">write_data</span><span class="p">,</span>

    <span class="kt">input</span> <span class="kt">bit</span> <span class="n">read</span><span class="p">,</span>
    <span class="kt">output</span> <span class="kt">bit</span> <span class="p">[</span><span class="mi">31</span><span class="o">:</span><span class="mi">0</span><span class="p">]</span> <span class="n">read_data</span>
    <span class="p">);</span>
</code></pre></div></div>

<p>I didn’t include an <code class="language-plaintext highlighter-rouge">address</code> signal to keep things simple. All bus operations will always target the <code class="language-plaintext highlighter-rouge">CTRL</code> register.</p>

<p>You can find the full code <a href="https://github.com/verification-gentleman-blog/comparison-of-formal-and-simulation">here</a>, including the verification environment, if you want to dig deeper into it or to experiment with it yourself.</p>

<h2 id="formal-verification">Formal Verification</h2>

<p>Before we start writing anything, let’s stop for a second and think about what we want to achieve. It’s true that we could write a few assertions about what the design is supposed whenever this or that is written. This would mean focusing on the implementation.</p>

<p>What is the most important thing that the design requirements try to ensure? All of them are there to make sure that the DUT is always in a legal configuration, where it can properly perform its function. Requirements like “writes with reserved values are ignored” or “writes with illegal combinations are ignored” merely serve to support this core requirement. The cool thing about formal verification is that we can focus on these core requirements.</p>

<p>To check these core requirements, we’ll use a gray-box verification approach. We’ll look directly at the internal DUT SFR. This way we can start writing properties without having to write any kind of infrastructure for the bus interface.</p>

<p>Of course, we could create a separate model of the DUT SFRs and write our properties using that. We could update it based on the bus operations that execute on the interface, similarly to how we would do it in a UVM-based testbench. This would not only require extra effort to implement the model and the monitoring, but it would increase the state space, making it more difficult for the tool to achieve proofs.</p>

<p>I was previously against any kind of white-box at block level, but I have since softened my stance, including when doing simulation. I now find it to be an acceptable trade-off, as long as it is done responsibly and in moderation. It should also only be done on parts of the design that are architecturally “visible” and that are relatively stable.</p>

<p>When accessing the values of the DUT’s internal <code class="language-plaintext highlighter-rouge">CTRL</code> register, we should try to protect ourselves from any implementation specific aspects that might change unexpectedly and cause a lot of rework on our side. For example, the designer might choose to define a single 32 bit vector, where the bit positions for the fields might match those in the specification. They might decide to have two separate signals, one for each field. There are many possibilities to choose from.</p>

<p>We can define our “references” to the internal signals using the following <strong>let</strong> statements:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">let</span> <span class="n">shape_in_sfr</span> <span class="o">=</span> <span class="n">shape_processor</span><span class="p">.</span><span class="n">ctrl_sfr</span><span class="p">.</span><span class="n">shape</span><span class="p">;</span>
<span class="n">let</span> <span class="n">operation_in_sfr</span> <span class="o">=</span> <span class="n">shape_processor</span><span class="p">.</span><span class="n">ctrl_sfr</span><span class="p">.</span><span class="n">operation</span><span class="p">;</span>
</code></pre></div></div>

<p>Our design currently uses a <strong>struct</strong> for the <code class="language-plaintext highlighter-rouge">CTRL</code> register, but if this were to ever change, we would only need to update these <strong>let</strong> statements.</p>

<p>To make our code more readable, we should model the encodings for the SFR fields using <strong>enums</strong>:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">typedef</span> <span class="kt">enum</span> <span class="kt">bit</span> <span class="p">[</span><span class="mi">2</span><span class="o">:</span><span class="mi">0</span><span class="p">]</span> <span class="o">{</span>
  <span class="n">CIRCLE</span> <span class="o">=</span> <span class="mb">'b001</span><span class="p">,</span>
  <span class="n">RECTANGLE</span> <span class="o">=</span> <span class="mb">'b010</span><span class="p">,</span>
  <span class="n">TRIANGLE</span> <span class="o">=</span> <span class="mb">'b100</span><span class="p">,</span>
  <span class="n">KEEP_SHAPE</span> <span class="o">=</span> <span class="mb">'1</span>
<span class="o">}</span> <span class="n">shape_e</span><span class="p">;</span>

<span class="k">typedef</span> <span class="kt">enum</span> <span class="kt">bit</span> <span class="p">[</span><span class="mi">6</span><span class="o">:</span><span class="mi">0</span><span class="p">]</span> <span class="o">{</span>
  <span class="n">PERIMETER</span> <span class="o">=</span> <span class="mb">'b000_0000</span><span class="p">,</span>
  <span class="n">AREA</span> <span class="o">=</span> <span class="mb">'b000_0001</span><span class="p">,</span>
  <span class="n">IS_SQUARE</span> <span class="o">=</span> <span class="mb">'b010_0000</span><span class="p">,</span>
  <span class="n">IS_EQUILATERAL</span> <span class="o">=</span> <span class="mb">'b100_0000</span><span class="p">,</span>
  <span class="n">IS_ISOSCELES</span> <span class="o">=</span> <span class="mb">'b100_0001</span><span class="p">,</span>
  <span class="n">KEEP_OPERATION</span> <span class="o">=</span> <span class="mb">'1</span>
<span class="o">}</span> <span class="n">operation_e</span><span class="p">;</span>
</code></pre></div></div>

<p>With the infrastructure laid out, it’s time to get to work! The most basic check we can do is to ensure that the values of the <code class="language-plaintext highlighter-rouge">CTRL</code> SFR fields will never have any of the reserved values. For the <code class="language-plaintext highlighter-rouge">SHAPE</code> field we would have the following assertion:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">no_reserved_shapes_in_sfr</span><span class="o">:</span> <span class="k">assert</span> <span class="k">property</span> <span class="p">(</span>
    <span class="o">!</span><span class="n">is_reserved_shape</span><span class="p">(</span><span class="n">shape_in_sfr</span><span class="p">));</span>
</code></pre></div></div>

<p>The <code class="language-plaintext highlighter-rouge">is_reserved_shape(...)</code> function will return <code class="language-plaintext highlighter-rouge">1</code> when it is supplied a value that doesn’t match any of the values defined in the <code class="language-plaintext highlighter-rouge">shape_e</code> type:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">function</span> <span class="kt">bit</span> <span class="n">is_reserved_shape</span><span class="p">(</span><span class="kt">bit</span> <span class="p">[</span><span class="mi">2</span><span class="o">:</span><span class="mi">0</span><span class="p">]</span> <span class="n">val</span><span class="p">);</span>
  <span class="k">return</span> <span class="o">!</span><span class="p">(</span><span class="n">val</span> <span class="k">inside</span> <span class="o">{</span> <span class="n">KEEP_SHAPE</span><span class="p">,</span> <span class="n">CIRCLE</span><span class="p">,</span> <span class="n">RECTANGLE</span><span class="p">,</span> <span class="n">TRIANGLE</span> <span class="o">}</span><span class="p">);</span>
<span class="k">endfunction</span>
</code></pre></div></div>

<p>(Ideally, we would have used a <code class="language-plaintext highlighter-rouge">$cast(...)</code> to check whether the bit vector argument can be converted to the desired <strong>enum</strong> type, but I couldn’t get this to work.)</p>

<p>If the DUT would not properly validate the value of the <code class="language-plaintext highlighter-rouge">SHAPE</code> field before writing it, then the assertion from above would catch it.</p>

<p>We would also need a similar assertion for the <code class="language-plaintext highlighter-rouge">OPERATION</code> field:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">no_reserved_operations_in_sfr</span><span class="o">:</span> <span class="k">assert</span> <span class="k">property</span> <span class="p">(</span>
    <span class="o">!</span><span class="n">is_reserved_operation</span><span class="p">(</span><span class="n">operation_in_sfr</span><span class="p">));</span>
</code></pre></div></div>

<p>While <code class="language-plaintext highlighter-rouge">KEEP_SHAPE</code> and <code class="language-plaintext highlighter-rouge">KEEP_OPERATION</code> are defined write values for the <code class="language-plaintext highlighter-rouge">CTRL</code> fields, it is not possible for the SFR to contain any of these values. We can check that the DUT doesn’t latch <code class="language-plaintext highlighter-rouge">KEEP_SHAPE</code> by mistake using the following assertion:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">no_keep_shape_in_sfr</span><span class="o">:</span> <span class="k">assert</span> <span class="k">property</span> <span class="p">(</span>
    <span class="n">shape_in_sfr</span> <span class="o">!=</span> <span class="n">KEEP_SHAPE</span><span class="p">);</span>
</code></pre></div></div>

<p>Also, for <code class="language-plaintext highlighter-rouge">KEEP_OPERATION</code> we would have:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">no_keep_operation_in_sfr</span><span class="o">:</span> <span class="k">assert</span> <span class="k">property</span> <span class="p">(</span>
    <span class="n">operation_in_sfr</span> <span class="o">!=</span> <span class="n">KEEP_OPERATION</span><span class="p">);</span>
</code></pre></div></div>

<p>We also want to ensure that we only ever see legal combinations in the <code class="language-plaintext highlighter-rouge">CTRL</code> SFR. For this, we need an extra assertion:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">only_legal_combinations_in_sfr</span><span class="o">:</span> <span class="k">assert</span> <span class="k">property</span> <span class="p">(</span>
    <span class="n">is_legal_combination</span><span class="p">(</span><span class="n">shape_in_sfr</span><span class="p">,</span> <span class="n">operation_in_sfr</span><span class="p">));</span>
</code></pre></div></div>

<p>The <code class="language-plaintext highlighter-rouge">is_legal_combination(...)</code> function models the rules that govern which <code class="language-plaintext highlighter-rouge">SHAPES</code> can be combined with which <code class="language-plaintext highlighter-rouge">OPERATIONS</code>:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">function</span> <span class="kt">bit</span> <span class="n">is_legal_combination</span><span class="p">(</span><span class="n">shape_e</span> <span class="n">shape</span><span class="p">,</span> <span class="n">operation_e</span> <span class="n">operation</span><span class="p">);</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">operation</span> <span class="k">inside</span> <span class="o">{</span> <span class="n">PERIMETER</span><span class="p">,</span> <span class="n">AREA</span> <span class="o">}</span><span class="p">)</span>
    <span class="k">return</span> <span class="mi">1</span><span class="p">;</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">operation</span> <span class="o">==</span> <span class="n">IS_SQUARE</span><span class="p">)</span>
    <span class="k">return</span> <span class="n">shape</span> <span class="o">==</span> <span class="n">RECTANGLE</span><span class="p">;</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">operation</span> <span class="k">inside</span> <span class="o">{</span> <span class="n">IS_EQUILATERAL</span><span class="p">,</span> <span class="n">IS_ISOSCELES</span> <span class="o">}</span><span class="p">)</span>
    <span class="k">return</span> <span class="n">shape</span> <span class="o">==</span> <span class="n">TRIANGLE</span><span class="p">;</span>
  <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="k">endfunction</span>
</code></pre></div></div>

<p>Ideally such modeling code should not be a one-to-one copy of the RTL code. Where the RTL compares bits, the modeling code uses <strong>enum</strong> values, which also makes it very readable.</p>

<p>It’s not the task of the <code class="language-plaintext highlighter-rouge">is_legal_combination(...)</code> function to model the behavior of <code class="language-plaintext highlighter-rouge">KEEP_SHAPE</code> or of <code class="language-plaintext highlighter-rouge">KEEP_OPERATION</code>. It should never be called with any of these values. The fact that it returns <code class="language-plaintext highlighter-rouge">0</code> if any of these values is passed as an argument is an implementation artifact. Normally, in simulation, I would trigger a fatal error in such cases, to make it clear to the caller that it’s doing something wrong. Sadly, I couldn’t get the tool to do this.</p>

<p>The assertions we wrote up to now will prove that our DUT can never be put in a faulty configuration. Unfortunately, they will also hold for a DUT that completely ignores writes (assuming, of course, that it comes out of reset with a legal combination of fields). This is because we haven’t made it a requirement for the DUT to update its fields based on the write data presented to it. We only said that should it update its fields, the resulting values must satisfy the assertions we wrote.</p>

<p>A very cheap way of making sure that the DUT updates its fields is to write a <strong>cover property</strong> that proves that each (proper) value of the <code class="language-plaintext highlighter-rouge">SHAPE</code> and <code class="language-plaintext highlighter-rouge">OPERATION</code> fields can be stored in the SFR. We’ll use the term “proper” to refer to all modes other than the two <code class="language-plaintext highlighter-rouge">KEEP_*</code> modes.</p>

<p>We can check that a <code class="language-plaintext highlighter-rouge">CIRCLE</code> can be seen in the <code class="language-plaintext highlighter-rouge">SHAPE</code> field using the following cover:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">circle_in_sfr</span><span class="o">:</span> <span class="k">cover</span> <span class="k">property</span> <span class="p">(</span>
    <span class="n">shape_in_sfr</span> <span class="o">==</span> <span class="n">CIRCLE</span><span class="p">);</span>
</code></pre></div></div>

<p>This won’t bring us much if <code class="language-plaintext highlighter-rouge">CIRCLE</code> is the reset value of the field. Simply coming out reset will be enough to show us a trace. We should also check that we can see a <code class="language-plaintext highlighter-rouge">RECTANGLE</code> or a <code class="language-plaintext highlighter-rouge">TRIANGLE</code>:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">rectangle_in_sfr</span><span class="o">:</span> <span class="k">cover</span> <span class="k">property</span> <span class="p">(</span>
    <span class="n">shape_in_sfr</span> <span class="o">==</span> <span class="n">RECTANGLE</span><span class="p">);</span>

<span class="nl">triangle_in_sfr:</span> <span class="k">cover</span> <span class="k">property</span> <span class="p">(</span>
    <span class="n">shape_in_sfr</span> <span class="o">==</span> <span class="n">TRIANGLE</span><span class="p">);</span>
</code></pre></div></div>

<p>The DUT will have to be able to update the field, otherwise we won’t get traces for all of the properties.</p>

<p>We’re assuming that the <code class="language-plaintext highlighter-rouge">CTRL</code> register can be reset, otherwise the tool could just show us the DUT starting up with any <code class="language-plaintext highlighter-rouge">SHAPE</code> value. In this case the covers would be trivially reachable. The starting value could also be a reserved value, though, which would be caught by our assertions. Indirectly, we are ensuring that the SFR is reset. Moreover, if the SFR would not have a reset signal, then the tool would generally warn us about this.</p>

<p>We should give the <code class="language-plaintext highlighter-rouge">OPERATION</code> field the same treatment to make sure that all its proper values are reachable. Writing a cover for each possible operation, like we did for shapes, could get pretty tedious, though. To save typing we could use a <code class="language-plaintext highlighter-rouge">generate</code> statement and have the tool do the looping for us:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">for</span> <span class="p">(</span><span class="k">genvar</span> <span class="n">operation</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">operation</span> <span class="o">&lt;</span> <span class="mi">2</span><span class="o">**</span><span class="p">$</span><span class="nb">bits</span><span class="p">(</span><span class="n">operation_e</span><span class="p">);</span> <span class="n">operation</span><span class="o">++</span><span class="p">)</span> <span class="k">begin</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">operation</span> <span class="k">inside</span> <span class="o">{</span> <span class="n">PERIMETER</span><span class="p">,</span> <span class="n">AREA</span><span class="p">,</span> <span class="n">IS_SQUARE</span><span class="p">,</span> <span class="n">IS_EQUILATERAL</span><span class="p">,</span> <span class="n">IS_ISOSCELES</span> <span class="o">}</span><span class="p">)</span> <span class="k">begin</span>
    <span class="nl">operation_in_sfr_seen:</span> <span class="k">cover</span> <span class="k">property</span> <span class="p">(</span>
        <span class="n">operation_in_sfr</span> <span class="o">==</span> <span class="n">operation</span><span class="p">);</span>
  <span class="k">end</span>
<span class="k">end</span>
</code></pre></div></div>

<p>The code suffers from some SystemVerilog limitations. <code class="language-plaintext highlighter-rouge">Genvars</code> are integers, so the names of the generated blocks won’t be very suggestive because they’ll contain the numeric values of the <strong>enum</strong> literals, not the literals themselves. It’s also not possible to loop over <strong>enums</strong> directly, which makes the code longer and invites duplication. (The SystemVerilog syntax for looping over <code class="language-plaintext highlighter-rouge">enums</code> is not that great anyway, but at least it can handle changes in the <strong>enum</strong> type.)</p>

<p>The assertions that we wrote up to now for the internal SFR values, together with the covers, give us a very solid base. They provide enough guidance to implement the design properly and to avoid many non-trivial bugs. If we had high confidence in our designer and a good testing setup at the integration level we could probably stop here. If we were to go for the gold and verify the design completely we would still need a few more properties.</p>

<p>Since we’re doing gray-box verification, we should also check that the SFR contents are delivered on the read data bus when a bus read is performed.</p>

<p>When working with the bus data, it would be really annoying to have to fiddle with bit positions to figure out what shape or operation we are getting as a result of the read. To help us extract the fields, we can define a <strong>struct</strong> with the same layout as the <code class="language-plaintext highlighter-rouge">CTRL</code> register:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">typedef</span> <span class="kt">struct</span> <span class="kt">packed</span> <span class="o">{</span>
  <span class="kt">bit</span> <span class="p">[</span><span class="mi">12</span><span class="o">:</span><span class="mi">0</span><span class="p">]</span> <span class="n">reserved1</span><span class="p">;</span>
  <span class="kt">bit</span> <span class="p">[</span><span class="mi">2</span><span class="o">:</span><span class="mi">0</span><span class="p">]</span> <span class="n">SHAPE</span><span class="p">;</span>
  <span class="kt">bit</span> <span class="p">[</span><span class="mi">8</span><span class="o">:</span><span class="mi">0</span><span class="p">]</span> <span class="n">reserved0</span><span class="p">;</span>
  <span class="kt">bit</span> <span class="p">[</span><span class="mi">6</span><span class="o">:</span><span class="mi">0</span><span class="p">]</span> <span class="n">OPERATION</span><span class="p">;</span>
<span class="o">}</span> <span class="n">ctrl_sfr_reg</span><span class="p">;</span>
</code></pre></div></div>

<p>We can convert the read data to this type, for easy access to the fields using the <strong>.</strong> operator:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">ctrl_sfr_reg</span> <span class="n">read_data_as_ctrl_sfr</span><span class="p">;</span>
<span class="k">assign</span> <span class="n">read_data_as_ctrl_sfr</span> <span class="o">=</span> <span class="n">read_data</span><span class="p">;</span>
</code></pre></div></div>

<p>To make the code that uses them shorter, we can define some <strong>let</strong> statements for the read values of the fields, like we did for the internal SFR:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">let</span> <span class="n">shape_on_read_bus</span> <span class="o">=</span> <span class="n">read_data_as_ctrl_sfr</span><span class="p">.</span><span class="n">SHAPE</span><span class="p">;</span>
<span class="n">let</span> <span class="n">operation_on_read_bus</span> <span class="o">=</span> <span class="n">read_data_as_ctrl_sfr</span><span class="p">.</span><span class="n">OPERATION</span><span class="p">;</span>
</code></pre></div></div>

<p>Now we can write an assertion for each of the fields:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">shape_delivered_as_read_data</span><span class="o">:</span> <span class="k">assert</span> <span class="k">property</span> <span class="p">(</span>
    <span class="n">read</span> <span class="o">|-&gt;</span> <span class="n">shape_on_read_bus</span> <span class="o">==</span> <span class="n">shape_in_sfr</span><span class="p">);</span>

<span class="nl">operation_delivered_as_read_data:</span> <span class="k">assert</span> <span class="k">property</span> <span class="p">(</span>
    <span class="n">read</span> <span class="o">|-&gt;</span> <span class="n">operation_on_read_bus</span> <span class="o">==</span> <span class="n">operation_in_sfr</span><span class="p">);</span>
</code></pre></div></div>

<p>We haven’t said anything about the behavior of the <code class="language-plaintext highlighter-rouge">KEEP_SHAPE</code> mode. For this, we’ll have to look at the data being written on the bus.</p>

<p>Before we look at the write data, though, we can write another assertion. We can check that the SFR is only ever updated as a result of a bus write:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">sfr_constant_if_no_write</span><span class="o">:</span> <span class="k">assert</span> <span class="k">property</span> <span class="p">(</span>
    <span class="o">!</span><span class="nb">write</span> <span class="o">|=&gt;</span> <span class="p">$</span><span class="nb">stable</span><span class="p">(</span><span class="n">shape_processor</span><span class="p">.</span><span class="n">ctrl_sfr</span><span class="p">));</span>
</code></pre></div></div>

<p>If the DUT were to change the value of the SFR when, for example, no access is taking place, this assertion would fail. This is a very powerful check, which is also very simple to write. It’s pretty typical to find bugs where the RTL code doesn’t properly sample the bus control signals.</p>

<p>We can do the same trick for the write data that we did with the read data, in order to get the values of the fields:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">ctrl_sfr_reg</span> <span class="n">write_data_as_ctrl_sfr</span><span class="p">;</span>
<span class="k">assign</span> <span class="n">write_data_as_ctrl_sfr</span> <span class="o">=</span> <span class="n">write_data</span><span class="p">;</span>

<span class="n">let</span> <span class="n">shape_on_write_bus</span> <span class="o">=</span> <span class="n">write_data_as_ctrl_sfr</span><span class="p">.</span><span class="n">SHAPE</span><span class="p">;</span>
<span class="n">let</span> <span class="n">operation_on_write_bus</span> <span class="o">=</span> <span class="n">write_data_as_ctrl_sfr</span><span class="p">.</span><span class="n">OPERATION</span><span class="p">;</span>
</code></pre></div></div>

<p>Now we can check that when we try to write <code class="language-plaintext highlighter-rouge">KEEP_SHAPE</code>, the value of the DUT’s SFR doesn’t change:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">shape_constant_if_keep_shape_write</span><span class="o">:</span> <span class="k">assert</span> <span class="k">property</span> <span class="p">(</span>
    <span class="nb">write</span> <span class="o">&amp;&amp;</span> <span class="n">shape_on_write_bus</span> <span class="o">==</span> <span class="n">KEEP_SHAPE</span> <span class="o">|=&gt;</span>
        <span class="p">$</span><span class="nb">stable</span><span class="p">(</span><span class="n">shape_in_sfr</span><span class="p">));</span>
</code></pre></div></div>

<p>We can do the same for <code class="language-plaintext highlighter-rouge">KEEP_OPERATION</code>:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">operation_constant_if_keep_operation_write</span><span class="o">:</span> <span class="k">assert</span> <span class="k">property</span> <span class="p">(</span>
    <span class="nb">write</span> <span class="o">&amp;&amp;</span> <span class="n">operation_on_write_bus</span> <span class="o">==</span> <span class="n">KEEP_OPERATION</span>  <span class="o">|=&gt;</span>
        <span class="p">$</span><span class="nb">stable</span><span class="p">(</span><span class="n">operation_in_sfr</span><span class="p">));</span>
</code></pre></div></div>

<p>The previous assertions don’t say anything about what should happen with the other field whenever a <code class="language-plaintext highlighter-rouge">KEEP_*</code> is written. For example, a DUT that completely ignores a write that contains <code class="language-plaintext highlighter-rouge">KEEP_SHAPE</code> and keeps the value of <code class="language-plaintext highlighter-rouge">OPERATION</code> as well will also satisfy the assertions. We can write a cover property to see that the DUT can update the value of <code class="language-plaintext highlighter-rouge">OPERATION</code> in such cases:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">operation_updated_when_keep_shape</span><span class="o">:</span> <span class="k">cover</span> <span class="k">property</span> <span class="p">(</span>
    <span class="nb">write</span> <span class="o">&amp;&amp;</span> <span class="n">shape_on_write_bus</span> <span class="o">==</span> <span class="n">KEEP_SHAPE</span> <span class="p">##</span><span class="mi">1</span> <span class="p">$</span><span class="nb">changed</span><span class="p">(</span><span class="n">operation_in_sfr</span><span class="p">));</span>
</code></pre></div></div>

<p>This cover will fail if the DUT completely ignores writes with <code class="language-plaintext highlighter-rouge">KEEP_SHAPE</code>.</p>

<p>Naturally, we can write a similar cover property for <code class="language-plaintext highlighter-rouge">KEEP_OPERATION</code>:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">shape_updated_when_keep_operation</span><span class="o">:</span> <span class="k">cover</span> <span class="k">property</span> <span class="p">(</span>
    <span class="nb">write</span> <span class="o">&amp;&amp;</span> <span class="n">operation_on_write_bus</span> <span class="o">==</span> <span class="n">KEEP_OPERATION</span> <span class="p">##</span><span class="mi">1</span> <span class="p">$</span><span class="nb">changed</span><span class="p">(</span><span class="n">shape_in_sfr</span><span class="p">));</span>
</code></pre></div></div>

<p>The properties we have don’t fully specify what should happen whenever we try to write a reserved value to one of the fields. A DUT that treats a write with a reserved <code class="language-plaintext highlighter-rouge">SHAPE</code> value the same way it treats a <code class="language-plaintext highlighter-rouge">KEEP_SHAPE</code> will also pass all checks. To solve this, we can add the following assertions:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">sfr_constant_if_reserved_shape_write</span><span class="o">:</span> <span class="k">assert</span> <span class="k">property</span> <span class="p">(</span>
    <span class="nb">write</span> <span class="o">&amp;&amp;</span> <span class="n">is_reserved_shape</span><span class="p">(</span><span class="n">shape_on_write_bus</span><span class="p">)</span> <span class="o">|=&gt;</span>
        <span class="p">$</span><span class="nb">stable</span><span class="p">(</span><span class="n">shape_processor</span><span class="p">.</span><span class="n">ctrl_sfr</span><span class="p">));</span>

<span class="nl">sfr_constant_if_reserved_operation_write:</span> <span class="k">assert</span> <span class="k">property</span> <span class="p">(</span>
    <span class="nb">write</span> <span class="o">&amp;&amp;</span> <span class="n">is_reserved_operation</span><span class="p">(</span><span class="n">operation_on_write_bus</span><span class="p">)</span> <span class="o">|=&gt;</span>
        <span class="p">$</span><span class="nb">stable</span><span class="p">(</span><span class="n">shape_processor</span><span class="p">.</span><span class="n">ctrl_sfr</span><span class="p">));</span>
</code></pre></div></div>

<p>With these assertions, we make sure that writes that contain reserved values are completely ignored.</p>

<p>It’s becoming more and more difficult to find a DUT that fulfills these properties, but doesn’t fulfill the specification. The kinds of faulty implementations that these properties won’t catch are starting to look like intentional mistakes. We’ve reached another point where we could probably just stop, but still be able to get a good night’s sleep, knowing that the design is in very good shape. We could also write a few more properties and leave no stone unturned where bugs could hide.</p>

<p>Let’s recall that whenever an illegal combination of <code class="language-plaintext highlighter-rouge">SHAPE</code> and <code class="language-plaintext highlighter-rouge">OPERATION</code> values is written, the DUT is supposed to ignore it. If, however, the DUT were to write some default combination into the SFR in such a case, for example the reset value of <code class="language-plaintext highlighter-rouge">(CIRCLE, PERIMETER)</code>, then none of the properties we have would fail. This doesn’t sound like the kind of mistake a designer would make when building the design from scratch. It might be an issue if a previous version of the specification used to require this behavior, in which case it would be possible to overlook the new requirement.</p>

<p>Writing a single assertion for this might get a bit more complicated because of the <code class="language-plaintext highlighter-rouge">KEEP_*</code> values, but we can split the problem into multiple cases.</p>

<p>First, we should check that illegal combinations of proper modes are ignored:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">sfr_constant_if_illegal_combination_write_of_proper_modes</span><span class="o">:</span> <span class="k">assert</span> <span class="k">property</span> <span class="p">(</span>
    <span class="nb">write</span> <span class="o">&amp;&amp;</span> <span class="n">shape_on_write_bus</span> <span class="o">!=</span> <span class="n">KEEP_SHAPE</span> <span class="o">&amp;&amp;</span> <span class="n">operation_on_write_bus</span> <span class="o">!=</span> <span class="n">KEEP_OPERATION</span>
        <span class="o">&amp;&amp;</span> <span class="o">!</span><span class="n">is_legal_combination</span><span class="p">(</span><span class="n">shape_on_write_bus</span><span class="p">,</span> <span class="n">operation_on_write_bus</span><span class="p">)</span> <span class="o">|=&gt;</span>
            <span class="p">$</span><span class="nb">stable</span><span class="p">(</span><span class="n">shape_processor</span><span class="p">.</span><span class="n">ctrl_sfr</span><span class="p">));</span>
</code></pre></div></div>

<p>The fact that we already have the <code class="language-plaintext highlighter-rouge">is_legal_combination(...)</code> function which can operate on proper modes will nudge us into thinking about this behavior as an own case.</p>

<p>The next case we have is when we are writing <code class="language-plaintext highlighter-rouge">KEEP_SHAPE</code>, but the resulting combination would be illegal. This can also be implemented using the <code class="language-plaintext highlighter-rouge">is_legal_combination(...)</code> function, but instead of taking the bus value for the <code class="language-plaintext highlighter-rouge">shape</code>, we take the value in the SFR:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">sfr_constant_if_illegal_combination_write_of_keep_shape</span><span class="o">:</span> <span class="k">assert</span> <span class="k">property</span> <span class="p">(</span>
    <span class="nb">write</span> <span class="o">&amp;&amp;</span> <span class="n">shape_on_write_bus</span> <span class="o">==</span> <span class="n">KEEP_SHAPE</span>
        <span class="o">&amp;&amp;</span> <span class="o">!</span><span class="n">is_legal_combination</span><span class="p">(</span><span class="n">shape_in_sfr</span><span class="p">,</span> <span class="n">operation_on_write_bus</span><span class="p">)</span> <span class="o">|=&gt;</span>
            <span class="p">$</span><span class="nb">stable</span><span class="p">(</span><span class="n">shape_processor</span><span class="p">.</span><span class="n">ctrl_sfr</span><span class="p">));</span>
</code></pre></div></div>

<p>Of course, we have to do the same for <code class="language-plaintext highlighter-rouge">KEEP_OPERATION</code>:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">sfr_constant_if_illegal_combination_write_of_keep_operation</span><span class="o">:</span> <span class="k">assert</span> <span class="k">property</span> <span class="p">(</span>
    <span class="nb">write</span> <span class="o">&amp;&amp;</span> <span class="n">operation_on_write_bus</span> <span class="o">==</span> <span class="n">KEEP_OPERATION</span>
        <span class="o">&amp;&amp;</span> <span class="o">!</span><span class="n">is_legal_combination</span><span class="p">(</span><span class="n">shape_on_write_bus</span><span class="p">,</span> <span class="n">operation_in_sfr</span><span class="p">)</span> <span class="o">|=&gt;</span>
            <span class="p">$</span><span class="nb">stable</span><span class="p">(</span><span class="n">shape_processor</span><span class="p">.</span><span class="n">ctrl_sfr</span><span class="p">));</span>
</code></pre></div></div>

<p>Now we can prove that the DUT always ignores illegal writes, regardless of the reason (either reserved value or illegal combination), as we have properties for each of the cases.</p>

<p>I’m having a really difficult time coming up with a faulty implementation that still passes the current set of properties. The best I can come up with at this point is a design that somehow writes a “twisted” version of the data given to it: instead of writing <code class="language-plaintext highlighter-rouge">CIRCLE</code>, it writes <code class="language-plaintext highlighter-rouge">RECTANGLE</code> and vice-versa, but only when also trying to write <code class="language-plaintext highlighter-rouge">PERIMETER</code> (otherwise we might get illegal combination in the SFR).</p>

<p>For this design maybe it isn’t that important to check that writes properly update the SFR fields, as there isn’t much that much room for error. For a design where one of the shapes can be disabled via a separate SFR bit I could see it becoming very important. Let’s imagine, for example, that the <code class="language-plaintext highlighter-rouge">CIRCLE</code> shape could be disabled depending on whether the <em>pi</em> computation unit is powered off. If this design also has a bug where it disables the <code class="language-plaintext highlighter-rouge">TRIANGLE</code> shape as well, we would not be able to find this if we only cover that the <code class="language-plaintext highlighter-rouge">SHAPE</code> field can be <code class="language-plaintext highlighter-rouge">TRIANGLE</code>. This is because the tool could always show us such traces when the <em>pi</em> computation unit is turned on.</p>

<p>To weed out any remaining pathological design behaviors we can write one more pair of assertions: that legal writes, that are supposed to update the SFR, do so properly for each of the fields. Here’s what the assertion would look like for <code class="language-plaintext highlighter-rouge">SHAPE</code>:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">legal_write_data_written_to_shape</span><span class="o">:</span> <span class="k">assert</span> <span class="k">property</span> <span class="p">(</span>
    <span class="nb">write</span> <span class="o">&amp;&amp;</span> <span class="n">is_legal_ctrl_write_data</span><span class="p">()</span> <span class="o">|=&gt;</span>
        <span class="n">shape_in_sfr</span> <span class="o">==</span> <span class="p">$</span><span class="nb">past</span><span class="p">(</span><span class="n">shape_on_write_bus</span><span class="p">));</span>
</code></pre></div></div>

<p>While we were able to write multiple assertions when dealing with the cases where the write had to be ignored, in this case we have to write one assertion. We have to model what it means for the write data to be legal and this means describing all the properties required of it. None of the fields are allowed to contain reserved values and the combination of fields is supposed to be legal:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">function</span> <span class="kt">bit</span> <span class="n">is_legal_ctrl_write_data</span><span class="p">();</span>
  <span class="k">return</span> <span class="o">!</span><span class="n">is_reserved_shape</span><span class="p">(</span><span class="n">shape_on_write_bus</span><span class="p">)</span>
      <span class="o">&amp;&amp;</span> <span class="o">!</span><span class="n">is_reserved_operation</span><span class="p">(</span><span class="n">operation_on_write_bus</span><span class="p">)</span>
      <span class="o">&amp;&amp;</span> <span class="n">is_legal_ctrl_write_data_combination</span><span class="p">();</span>
<span class="k">endfunction</span>
</code></pre></div></div>

<p>The combination being legal is defined differently, depending on whether we are dealing with a <code class="language-plaintext highlighter-rouge">KEEP_*</code> or with a proper mode:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">function</span> <span class="kt">bit</span> <span class="n">is_legal_ctrl_write_data_combination</span><span class="p">();</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">shape_on_write_bus</span> <span class="o">==</span> <span class="n">KEEP_SHAPE</span><span class="p">)</span>
    <span class="k">return</span> <span class="n">is_legal_combination</span><span class="p">(</span><span class="n">shape_in_sfr</span><span class="p">,</span> <span class="n">operation_on_write_bus</span><span class="p">);</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">operation_on_write_bus</span> <span class="o">==</span> <span class="n">KEEP_OPERATION</span><span class="p">)</span>
    <span class="k">return</span> <span class="n">is_legal_combination</span><span class="p">(</span><span class="n">shape_on_write_bus</span><span class="p">,</span> <span class="n">operation_in_sfr</span><span class="p">);</span>
  <span class="k">return</span> <span class="n">is_legal_combination</span><span class="p">(</span><span class="n">shape_on_write_bus</span><span class="p">,</span> <span class="n">operation_on_write_bus</span><span class="p">);</span>
<span class="k">endfunction</span>
</code></pre></div></div>

<p>If we try to prove this assertion, we’ll notice that it fails. It will complain that it can’t write <code class="language-plaintext highlighter-rouge">KEEP_SHAPE</code> into the SFR. This is because <code class="language-plaintext highlighter-rouge">KEEP_SHAPE</code> is not a value that leads to an update of the <code class="language-plaintext highlighter-rouge">SHAPE</code> field. We have to exclude this case and then the assertion will pass:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">legal_write_data_written_to_shape</span><span class="o">:</span> <span class="k">assert</span> <span class="k">property</span> <span class="p">(</span>
    <span class="nb">write</span> <span class="o">&amp;&amp;</span> <span class="n">is_legal_ctrl_write_data</span><span class="p">()</span> <span class="o">&amp;&amp;</span> <span class="n">shape_on_write_bus</span> <span class="o">!=</span> <span class="n">KEEP_SHAPE</span> <span class="o">|=&gt;</span>
        <span class="n">shape_in_sfr</span> <span class="o">==</span> <span class="p">$</span><span class="nb">past</span><span class="p">(</span><span class="n">shape_on_write_bus</span><span class="p">));</span>
</code></pre></div></div>

<p>Now imagine that the design would have contained the same bug. We could have let something slip through, since this assertion would have passed. Fortunately, even if this were the case, we still have the assertions on the internal SFR, which disallow <code class="language-plaintext highlighter-rouge">KEEP_SHAPE</code> as a value. This is the power of thinking about the core requirements of the design!</p>

<p>It’s not that we wouldn’t be able to do something similar in simulation. We could very well write checks on the internal SFR, alongside our register modeling which describes which writes are legal and which are not. It’s just that we probably wouldn’t, because our thinking is very focused on describing cause/effect relationships. We would probably stop after finishing with our register modeling and move on to the next thing.</p>

<p>For completeness, we also need a property for the <code class="language-plaintext highlighter-rouge">OPERATION</code> field:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">legal_write_data_written_to_operation</span><span class="o">:</span> <span class="k">assert</span> <span class="k">property</span> <span class="p">(</span>
    <span class="nb">write</span> <span class="o">&amp;&amp;</span> <span class="n">is_legal_ctrl_write_data</span><span class="p">()</span> <span class="o">&amp;&amp;</span> <span class="n">operation_on_write_bus</span> <span class="o">!=</span> <span class="n">KEEP_OPERATION</span> <span class="o">|=&gt;</span>
        <span class="n">operation_in_sfr</span> <span class="o">==</span> <span class="p">$</span><span class="nb">past</span><span class="p">(</span><span class="n">operation_on_write_bus</span><span class="p">));</span>
</code></pre></div></div>

<p>Before we end, I would like to revisit illegal writes that are supposed to be ignored. Now that we have a <code class="language-plaintext highlighter-rouge">is_legal_ctrl_write_data()</code> function, we could use it to write a single assertion to handle all cases of illegal writes, which are supposed to be ignored:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">sfr_constant_if_illegal_write</span><span class="o">:</span> <span class="k">assert</span> <span class="k">property</span> <span class="p">(</span>
    <span class="nb">write</span> <span class="o">&amp;&amp;</span> <span class="o">!</span><span class="n">is_legal_ctrl_write_data</span><span class="p">()</span> <span class="o">|=&gt;</span>
        <span class="p">$</span><span class="nb">stable</span><span class="p">(</span><span class="n">shape_processor</span><span class="p">.</span><span class="n">ctrl_sfr</span><span class="p">));</span>
</code></pre></div></div>

<p>This could replace the other assertions that we have that handle each illegal case separately.</p>

<p>Depending on the situation, it might be more advantageous to have either a single assertion for a requirement or to split it into multiple assertions. Multiple assertions are easier to debug and might be easier for the tool to prove (at least for big designs), because we are asking it to give us answers to slightly easier questions. Writing a single assertion has the advantage that it requires less code. It’s easier to handle changes to the requirements when there are less places to update.</p>

<p>For this design I would go with the single property.</p>

<h2 id="conclusions">Conclusions</h2>

<p>We’ve seen how formal verification nudges us to think about requirements, not about how to implement a testbench that is a faithful representation of the design.</p>

<p>We made our properties very readable and modular, which allowed us to tackle the verification task in incremental chunks. We should strive to avoid replicating the design and to make the properties read like sentences in the specification. In the end, our property checking environment doesn’t have many more lines of code than the design itself.</p>

<p>We also saw that formal verification doesn’t have to be an “all or nothing” proposition. Depending on our level of risk aversion we could decide to live with only a sub-set of checks, but still get high design quality. We can focus on the things that are truly important or difficult and not spend too much effort on the parts that are unlikely to have bugs.</p>

<p>Stay tuned for part 2, where we’ll build a UVM testbench for the same design.</p>]]></content><author><name>Tudor Timi</name></author><category term="Formal Verification" /><category term="SystemVerilog" /><summary type="html"><![CDATA[I’ve talked a lot about constrained random verification on the blog, but now it’s time to branch out to formal verification. As a fun first post on the topic, I thought we could do a comparative study. We can take a design and write two verification environments for it, one using formal verification and the other using simulation, based on UVM. Once we’re done, it should be very interesting to be able to look at them side-by-side and to do an analysis.]]></summary></entry><entry><title type="html">Favor Composition Over Inheritance - Even for Constraints</title><link href="https://blog.verificationgentleman.com/2020/03/29/composition-for-constraints.html" rel="alternate" type="text/html" title="Favor Composition Over Inheritance - Even for Constraints" /><published>2020-03-29T17:02:00+02:00</published><updated>2020-03-29T17:02:00+02:00</updated><id>https://blog.verificationgentleman.com/2020/03/29/composition-for-constraints</id><content type="html" xml:base="https://blog.verificationgentleman.com/2020/03/29/composition-for-constraints.html"><![CDATA[<p>Simulation is currently the dominant functional verification technique, with constrained random verification the most widely used methodology. While producing random data is a big part of it, letting the solver blindly generate stimulus isn’t going to be very efficient. Constraints are needed to guide the stimulus toward interesting scenarios.</p>

<p>A good constrained random test suite contains a mixture of tests with varying degrees of randomness. This is achieved by progressively adding constraints to tests to reduce their randomness. This is best explained with an example.</p>

<p>Let’s assume we’re verifying a device that can handle read and write accesses to locations in its address map. These accesses can either be done in secure mode or in non-secure mode. We model an access using a UVM sequence item:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">class</span> <span class="n">sequence_item</span> <span class="k">extends</span> <span class="n">uvm_sequence_item</span><span class="p">;</span>

  <span class="k">typedef</span> <span class="kt">enum</span> <span class="o">{</span>
    <span class="n">READ</span><span class="p">,</span>
    <span class="n">WRITE</span>
  <span class="o">}</span> <span class="n">direction_e</span><span class="p">;</span>

  <span class="k">typedef</span> <span class="kt">enum</span> <span class="o">{</span>
    <span class="n">SECURE</span><span class="p">,</span>
    <span class="n">NONSECURE</span>
  <span class="o">}</span> <span class="n">sec_mode_e</span><span class="p">;</span>

  <span class="k">rand</span> <span class="n">direction_e</span> <span class="n">direction</span><span class="p">;</span>
  <span class="k">rand</span> <span class="kt">bit</span> <span class="p">[</span><span class="mi">31</span><span class="o">:</span><span class="mi">0</span><span class="p">]</span> <span class="n">address</span><span class="p">;</span>
  <span class="k">rand</span> <span class="n">sec_mode_e</span> <span class="n">sec_mode</span><span class="p">;</span>

  <span class="c1">// ...</span>
<span class="k">endclass</span>
</code></pre></div></div>

<p>Not all accesses are legal and illegal accesses would be rejected by the device.</p>

<p>Only certain address ranges are mapped, while accesses to unmapped addresses are illegal. If we were to write a test that only accesses mapped addresses, we would have to add the following constraints to generated items:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">constraint</span> <span class="n">only_mapped_addresses</span> <span class="o">{</span>
  <span class="n">address</span> <span class="k">inside</span> <span class="o">{</span>
      <span class="p">[</span><span class="n">CODE_START_ADDR</span><span class="o">:</span><span class="n">CODE_END_ADDR</span><span class="p">],</span>
      <span class="p">[</span><span class="n">SRAM_START_ADDR</span><span class="o">:</span><span class="n">SRAM_END_ADDR</span><span class="p">],</span>
      <span class="p">[</span><span class="n">PERIPHERAL_START_ADDR</span><span class="o">:</span><span class="n">PERIPHERAL_END_ADDR</span><span class="p">]</span> <span class="o">}</span><span class="p">;</span>
<span class="o">}</span>
</code></pre></div></div>

<p>Our device also only allows writes to aligned addresses. For a 32-bit bus, this would mean that the lowest two address bits have to be 0:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">constraint</span> <span class="n">only_writes_to_aligned_addresses</span> <span class="o">{</span>
  <span class="n">direction</span> <span class="o">==</span> <span class="n">WRITE</span><span class="p">;</span>
  <span class="n">address</span><span class="p">[</span><span class="mi">1</span><span class="o">:</span><span class="mi">0</span><span class="p">]</span> <span class="o">==</span> <span class="mi">0</span><span class="p">;</span>
<span class="o">}</span>
</code></pre></div></div>

<p>Lastly, certain ranges of our device’s address map are restricted to secure code. Let’s assume that the address map is split into 16 regions of 256 MB each. Within each of these regions, the lower half is reserved for secure accesses. This means that bit 27 of the address is always 0 for a secure access:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">constraint</span> <span class="n">only_secure_accesses_to_lower_half_of_range</span> <span class="o">{</span>
  <span class="n">sec_mode</span> <span class="o">==</span> <span class="n">SECURE</span><span class="p">;</span>
  <span class="n">address</span><span class="p">[</span><span class="mi">27</span><span class="p">]</span> <span class="o">==</span> <span class="mi">0</span><span class="p">;</span>
<span class="o">}</span>
</code></pre></div></div>

<p>The test suite for this device would contain a random test where unconstrained items are generated. One test would be directed toward generating accesses to mapped addresses, another test would only perform writes to aligned addresses, while another test would perform only secure accesses. At the same time, we would also need tests that lie at the intersection of the three features, so we would want tests that do pairwise combinations: aligned writes to mapped addresses, aligned writes in secure mode and secure access to mapped addresses. Finally, we also need a test that combines all three and only does secure writes to mapped addresses.</p>

<p>(While a real test suite would definitely need a lot more classes of tests, this post isn’t focused on verification planning, but on the mechanical aspects of implementing a robust constraint management strategy, so please ignore the simplicity of the example.)</p>

<p>It might be the case that these behaviors will get tweaked over time as the project moves forward or as a new derivative of the device is developed. The address map might change as regions are moved, removed or resized, or new regions are added. The bus width might change, which would change which addresses are aligned, or we could get a feature request to implement writes of other granularities (e.g. half-word). The definition of secure regions could also change or they could become configurable via special function registers. Any of these changes should be easy to handle and shouldn’t require massive changes to the verification code.</p>

<p>Let’s skip the obvious idea of putting all constraints into the sequence item class and activating/deactivating them selectively based on the test. This won’t scale for real projects, where we would have many more constraints, which would make the code unreadable.</p>

<h2 id="using-mixins">Using mixins</h2>

<p>Quite a while back I wrote about <a href="/2015/03/28/mixing-in-constraints.html">how to use mixins to manage constraints</a>.</p>

<p>The mixin approach is flexible, because it allows us to handle each aspect individually. Instead of having all constraints in a single class, we can have one mixin for each constrained feature.</p>

<p>We need one for mapped addresses:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">class</span> <span class="n">only_mapped_addresses_mixin</span> <span class="p">#(</span><span class="k">type</span> <span class="n">T</span> <span class="o">=</span> <span class="n">sequence_item</span><span class="p">)</span> <span class="k">extends</span> <span class="n">T</span><span class="p">;</span>

  <span class="k">constraint</span> <span class="n">only_mapped_addresses</span> <span class="o">{</span>
    <span class="n">address</span> <span class="k">inside</span> <span class="o">{</span>
        <span class="p">[</span><span class="n">CODE_START_ADDR</span><span class="o">:</span><span class="n">CODE_END_ADDR</span><span class="p">],</span>
        <span class="p">[</span><span class="n">SRAM_START_ADDR</span><span class="o">:</span><span class="n">SRAM_END_ADDR</span><span class="p">],</span>
        <span class="p">[</span><span class="n">PERIPHERAL_START_ADDR</span><span class="o">:</span><span class="n">PERIPHERAL_END_ADDR</span><span class="p">]</span> <span class="o">}</span><span class="p">;</span>
  <span class="o">}</span>

  <span class="c1">// ...</span>
<span class="k">endclass</span>
</code></pre></div></div>

<p>We also need one for writes:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">class</span> <span class="n">only_legal_writes_mixin</span> <span class="p">#(</span><span class="k">type</span> <span class="n">T</span> <span class="o">=</span> <span class="n">sequence_item</span><span class="p">)</span> <span class="k">extends</span> <span class="n">T</span><span class="p">;</span>

  <span class="k">constraint</span> <span class="n">only_writes_to_aligned_addresses</span> <span class="o">{</span>
    <span class="n">direction</span> <span class="o">==</span> <span class="n">WRITE</span><span class="p">;</span>
    <span class="n">address</span><span class="p">[</span><span class="mi">1</span><span class="o">:</span><span class="mi">0</span><span class="p">]</span> <span class="o">==</span> <span class="mi">0</span><span class="p">;</span>
  <span class="o">}</span>

  <span class="c1">// ...</span>
<span class="k">endclass</span>
</code></pre></div></div>

<p>Finally, we need a mixin for secure accesses:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">class</span> <span class="n">only_legal_secure_accesses_mixin</span> <span class="p">#(</span><span class="k">type</span> <span class="n">T</span> <span class="o">=</span> <span class="n">sequence_item</span><span class="p">)</span> <span class="k">extends</span> <span class="n">T</span><span class="p">;</span>

  <span class="k">constraint</span> <span class="n">only_secure_accesses_to_lower_half_of_range</span> <span class="o">{</span>
    <span class="n">sec_mode</span> <span class="o">==</span> <span class="n">SECURE</span><span class="p">;</span>
    <span class="n">address</span><span class="p">[</span><span class="mi">27</span><span class="p">]</span> <span class="o">==</span> <span class="mi">0</span><span class="p">;</span>
  <span class="o">}</span>

  <span class="c1">// ...</span>
<span class="k">endclass</span>
</code></pre></div></div>

<p>Assuming that we have a random test that starts regular sequence items, we would use these mixins to write our more directed tests by replacing the original sequence item type with one with constraints mixed in.</p>

<p>The test that only accesses mapped addresses would do the following factory override:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">class</span> <span class="n">test_mapped_addresses</span> <span class="k">extends</span> <span class="n">test_all_random</span><span class="p">;</span>

  <span class="k">protected</span> <span class="kt">virtual</span> <span class="k">function</span> <span class="kt">void</span> <span class="n">set_factory_overrides</span><span class="p">();</span>
    <span class="n">sequence_item</span><span class="o">::</span><span class="n">type_id</span><span class="o">::</span><span class="n">set_type_override</span><span class="p">(</span>
        <span class="n">only_mapped_addresses_mixin</span> <span class="p">#(</span><span class="n">sequence_item</span><span class="p">)</span><span class="o">::</span><span class="n">get_type</span><span class="p">());</span>
  <span class="k">endfunction</span>

  <span class="c1">// ...</span>
<span class="k">endclass</span>
</code></pre></div></div>

<p>The other two feature tests would look similar, but would use their respective mixins.</p>

<p>To only perform writes to mapped addresses we would need to chain the two mixins:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">class</span> <span class="n">test_legal_writes_to_mapped_addresses</span> <span class="k">extends</span> <span class="n">test_all_random</span><span class="p">;</span>

  <span class="k">protected</span> <span class="kt">virtual</span> <span class="k">function</span> <span class="kt">void</span> <span class="n">set_factory_overrides</span><span class="p">();</span>
    <span class="n">sequence_item</span><span class="o">::</span><span class="n">type_id</span><span class="o">::</span><span class="n">set_type_override</span><span class="p">(</span>
        <span class="n">only_legal_writes_mixin</span> <span class="p">#(</span><span class="n">only_mapped_addresses_mixin</span> <span class="p">#(</span><span class="n">sequence_item</span><span class="p">))</span><span class="o">::</span><span class="n">get_type</span><span class="p">());</span>
  <span class="k">endfunction</span>

  <span class="c1">// ...</span>
<span class="k">endclass</span>
</code></pre></div></div>

<p>Of course, we would do the same to handle the other two pairs.</p>

<p>Similarly, we could use the same principle to combine all three features:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">class</span> <span class="n">test_legal_writes_to_mapped_addresses_in_secure_mode</span> <span class="k">extends</span> <span class="n">test_all_random</span><span class="p">;</span>

  <span class="k">protected</span> <span class="kt">virtual</span> <span class="k">function</span> <span class="kt">void</span> <span class="n">set_factory_overrides</span><span class="p">();</span>
    <span class="n">sequence_item</span><span class="o">::</span><span class="n">type_id</span><span class="o">::</span><span class="n">set_type_override</span><span class="p">(</span>
        <span class="n">only_legal_writes_mixin</span> <span class="p">#(</span>
            <span class="n">only_mapped_addresses_mixin</span> <span class="p">#(</span>
                <span class="n">only_legal_secure_accesses_mixin</span> <span class="p">#(</span><span class="n">sequence_item</span><span class="p">)))</span><span class="o">::</span><span class="n">get_type</span><span class="p">());</span>
  <span class="k">endfunction</span>

  <span class="c1">// ...</span>
<span class="k">endclass</span>
</code></pre></div></div>

<p>The mixin approach comes with some issues, though.</p>

<p>Constraints are always polymorphic, so we have to be very careful to use unique constraint names across all mixins. Applying two different mixins that use the same constraint name would result in only the outer mixin’s constraints being applied, because it would override the constraint defined in the inner mixin. It’s very easy to run into this issue when using copy/paste to define a new mixin and forgetting to change the name of the constraint. Frustration will follow, as the code looks right, but leads to unexpected results. Moreover, the more mixins are used in the code base, the easier it is for constraint name collisions to happen.</p>

<p>Chaining of mixins is not particularly readable. It is bearable for one or two levels, but the more levels there are, the worse it’s going to get.</p>

<p>Finally, using mixins will cause the number of types in our code to explode. Each mixin on top of a class will create a new type. From a coding standpoint this isn’t such a big deal, as we won’t be referencing those types directly. The more types we have, though, the longer our compile times are going to get. Also, note that for the compiler <em>mixin1 #(mixin2 #(some_class))</em> is a distinct type from <em>mixin2 #(mixin1 #(some_class))</em>, regardless if it results in the “same” class. It’s very easy to use <em>mixin1 #(mixin2 #(some_class))</em> in one test, but use <em>mixin3 #(mixin2 #(mixin1 #(some_class)))</em> in another, which would make the compiler “see” an extra type.</p>

<p>The mixin pattern uses inheritance, which doesn’t match the call to action in the post title, so obviously we’re not going to stop here.</p>

<h2 id="using-aspect-oriented-programming">Using aspect oriented programming</h2>

<p>It’s much easier to write our test family using aspect oriented programming (AOP). AOP allows us to alter the definition of a class from a different file. Even though SystemSystemverilog doesn’t support AOP, I’d still like to show an example in e, as it can provide us with some hints into how we could improve the mixin-base solution.</p>

<p>(Please note that the following code may not be idiomatic, so don’t take it as a reference on how to handle constraints in e.)</p>

<p>Our sequence item definition would look similar:</p>

<pre><code class="language-e">&lt;'
struct sequence_item like any_sequence_item {

  direction: direction_e;
  address: uint(bits: 32);
  sec_mode: sec_mode_e;

};
'&gt;
</code></pre>

<p>In our test that only does mapped accesses, we would tell the compiler to add the constraint to the sequence item:</p>

<pre><code class="language-e">&lt;'
import test_all_random;

extend sequence_item {
  keep address in [CODE_START_ADDR..CODE_END_ADDR] or
      address in [SRAM_START_ADDR..SRAM_END_ADDR] or
      address in [PERIPHERAL_START_ADDR..PERIPHERAL_END_ADDR];
};
'&gt;
</code></pre>

<p>This does not result in a new type. It tweaks the existing <em>sequence_item</em> type for the duration of that test.</p>

<p>If we would like to reuse the constraint in the test that only writes to mapped addresses, we could put the extension into its own file. We could do the same for the other extensions that handle the other features. This would allow each test to load the relevant extension files. For example, for legal writes to mapped addresses we would have:</p>

<pre><code class="language-e">&lt;'
import test_all_random;
import constraints/only_legal_writes;
import constraints/only_mapped_addresses;
'&gt;
</code></pre>

<p>The file structure is similar to what we had when we used mixins, but the code is much cleaner.</p>

<p>Pay special attention to the natural language description of what we are doing: in <em>test_mapped_addresses</em> we are adding the constraint to the <em>sequence_item</em> type.</p>

<h2 id="using-constraint-objects">Using constraint objects</h2>

<p>Regular object oriented programming doesn’t allow us to change type definitions. What we can do, however, is build our code in such a way as to allow it to be extended when it is being used.</p>

<p>Back in 2015, there was an <a href="http://events.dvcon.org/2015/proceedings/papers/04P_11.pdf">exciting DVCon paper</a> that presented how to add constraints using composition. It showed how to add additional constraints to an instance of an object without changing the type of that object. This is done by encapsulating the constraints into their own objects which extend the behavior of the original object’s <code class="language-plaintext highlighter-rouge">randomize()</code> function. Have a quick look at the paper before proceeding, to understand the exact way this is done.</p>

<p>While the paper shows how to add constraints to object instances, we can extend the approach to add constraints globally, to all instances of a type. If we look back at the AOP case from before, this would be conceptually similar to what we were doing there. We would be emulating the addition of constraints to the <em>sequence_item</em> type.</p>

<p>The paper makes an attempt at global constraints in its final section, by using the UVM configuration DB. While that approach works, I feel that it is not expressive enough. A better API, consisting of a static function to add constraints globally, would make the code much more readable than a very verbose config DB <code class="language-plaintext highlighter-rouge">set(...)</code> call.</p>

<p>To get the extensibility we want, we have to set up the necessary infrastructure for it. If the sequence item class is under our control, we can modify it directly. Alternatively, if the sequence item is part of an external UVC package, we can define a sub-class which contains the necessary code.</p>

<p>We’ll assume that <em>sequence_item</em> can’t be changed and we’ll create a new <em>constrained_sequence_item</em> class. We would either use this sub-class in our sequences directly or use a factory override.</p>

<p>To execute code that affects all instances, the sequence item class needs a static function through which constraints are added:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">class</span> <span class="n">constrained_sequence_item</span> <span class="k">extends</span> <span class="n">sequence_item</span><span class="p">;</span>

  <span class="kt">static</span> <span class="k">function</span> <span class="kt">void</span> <span class="n">add_global_constraint</span><span class="p">(</span><span class="n">abstract_constraint</span> <span class="n">c</span><span class="p">);</span>
    <span class="c1">// ...</span>
  <span class="k">endfunction</span>

  <span class="c1">// ...</span>
<span class="k">endclass</span>
</code></pre></div></div>

<p>The <em>abstract_constraint</em> class would be the base class for our constraints and would provide us with a reference to the object that is being randomized:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">virtual</span> <span class="kt">class</span> <span class="n">abstract_constraint</span><span class="p">;</span>

  <span class="k">protected</span> <span class="n">sequence_item</span> <span class="n">object</span><span class="p">;</span>

  <span class="k">function</span> <span class="kt">void</span> <span class="n">set_object</span><span class="p">(</span><span class="n">sequence_item</span> <span class="n">object</span><span class="p">);</span>
    <span class="k">this</span><span class="p">.</span><span class="n">object</span> <span class="o">=</span> <span class="n">object</span><span class="p">;</span>
  <span class="k">endfunction</span>

<span class="k">endclass</span>
</code></pre></div></div>

<p>The code to handle global constraints is similar to the one presented in the paper. We store all global constraints in a static array:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">class</span> <span class="n">constrained_sequence_item</span> <span class="k">extends</span> <span class="n">sequence_item</span><span class="p">;</span>

  <span class="k">local</span> <span class="kt">static</span> <span class="k">rand</span> <span class="n">abstract_constraint</span> <span class="n">global_constraints</span><span class="p">[$];</span>

  <span class="kt">static</span> <span class="k">function</span> <span class="kt">void</span> <span class="n">add_global_constraint</span><span class="p">(</span><span class="n">abstract_constraint</span> <span class="n">c</span><span class="p">);</span>
     <span class="n">global_constraints</span><span class="p">.</span><span class="n">push_back</span><span class="p">(</span><span class="n">c</span><span class="p">);</span>
  <span class="k">endfunction</span>

  <span class="c1">// ...</span>
<span class="k">endclass</span>
</code></pre></div></div>

<p>Before randomizing a sequence item instance, we have to set up the constraint objects to point to it:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">class</span> <span class="n">constrained_sequence_item</span> <span class="k">extends</span> <span class="n">sequence_item</span><span class="p">;</span>

  <span class="k">function</span> <span class="kt">void</span> <span class="n">pre_randomize</span><span class="p">();</span>
    <span class="k">foreach</span> <span class="p">(</span><span class="n">global_constraints</span><span class="p">[</span><span class="n">i</span><span class="p">])</span>
      <span class="n">global_constraints</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">set_object</span><span class="p">(</span><span class="k">this</span><span class="p">);</span>
  <span class="k">endfunction</span>

  <span class="c1">// ...</span>
<span class="k">endclass</span>
</code></pre></div></div>

<p>With the infrastructure set up, we can move on. We encapsulate the constraints for our features into their own constraint classes:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">class</span> <span class="n">only_mapped_addresses_constraint</span> <span class="k">extends</span> <span class="n">abstract_constraint</span> <span class="p">#(</span><span class="n">sequence_item</span><span class="p">);</span>

  <span class="k">constraint</span> <span class="n">c</span> <span class="o">{</span>
    <span class="n">object</span><span class="p">.</span><span class="n">address</span> <span class="k">inside</span> <span class="o">{</span>
        <span class="p">[</span><span class="n">CODE_START_ADDR</span><span class="o">:</span><span class="n">CODE_END_ADDR</span><span class="p">],</span>
        <span class="p">[</span><span class="n">SRAM_START_ADDR</span><span class="o">:</span><span class="n">SRAM_END_ADDR</span><span class="p">],</span>
        <span class="p">[</span><span class="n">PERIPHERAL_START_ADDR</span><span class="o">:</span><span class="n">PERIPHERAL_END_ADDR</span><span class="p">]</span> <span class="o">}</span><span class="p">;</span>
  <span class="o">}</span>

<span class="k">endclass</span>
</code></pre></div></div>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">class</span> <span class="n">only_legal_writes_constraint</span> <span class="k">extends</span> <span class="n">abstract_constraint</span> <span class="p">#(</span><span class="n">sequence_item</span><span class="p">);</span>

  <span class="k">constraint</span> <span class="n">c</span> <span class="o">{</span>
    <span class="n">object</span><span class="p">.</span><span class="n">direction</span> <span class="o">==</span> <span class="n">sequence_item</span><span class="o">::</span><span class="n">WRITE</span><span class="p">;</span>
    <span class="n">object</span><span class="p">.</span><span class="n">address</span><span class="p">[</span><span class="mi">1</span><span class="o">:</span><span class="mi">0</span><span class="p">]</span> <span class="o">==</span> <span class="mi">0</span><span class="p">;</span>
  <span class="o">}</span>

<span class="k">endclass</span>
</code></pre></div></div>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">class</span> <span class="n">only_legal_secure_accesses_constraint</span> <span class="k">extends</span> <span class="n">abstract_constraint</span> <span class="p">#(</span><span class="n">sequence_item</span><span class="p">);</span>

  <span class="k">constraint</span> <span class="n">c</span> <span class="o">{</span>
    <span class="n">object</span><span class="p">.</span><span class="n">sec_mode</span> <span class="o">==</span> <span class="n">sequence_item</span><span class="o">::</span><span class="n">SECURE</span><span class="p">;</span>
    <span class="n">object</span><span class="p">.</span><span class="n">address</span><span class="p">[</span><span class="mi">27</span><span class="p">]</span> <span class="o">==</span> <span class="mi">0</span><span class="p">;</span>
  <span class="o">}</span>

<span class="k">endclass</span>
</code></pre></div></div>

<p>In the test that only accesses mapped addresses we would make sure to add the required constraints:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">class</span> <span class="n">test_mapped_addresses</span> <span class="k">extends</span> <span class="n">test_all_random</span><span class="p">;</span>

  <span class="k">protected</span> <span class="kt">virtual</span> <span class="k">function</span> <span class="kt">void</span> <span class="n">add_constraints</span><span class="p">();</span>
    <span class="n">only_mapped_addresses_constraint</span> <span class="n">c</span> <span class="o">=</span> <span class="k">new</span><span class="p">();</span>
    <span class="n">constrained_sequence_item</span><span class="o">::</span><span class="n">add_global_constraint</span><span class="p">(</span><span class="n">c</span><span class="p">);</span>
  <span class="k">endfunction</span>

  <span class="c1">// ...</span>
<span class="k">endclass</span>
</code></pre></div></div>

<p>The <em>add_constraints()</em> function should be called before any sequence items are started. A good place to call it from is the <em>end_of_elaboration_phase(…)</em> function.</p>

<p>In the other feature oriented tests we would simply add their respective constraints.</p>

<p>For the test that does writes to mapped addresses we just need to make sure that both constraints are added. We could do this by extending the random test and making two <em>add_global_constraint(…)</em> calls, one for each constraint object:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">class</span> <span class="n">test_legal_writes_to_mapped_addresses</span> <span class="k">extends</span> <span class="n">test_random</span><span class="p">;</span>

  <span class="k">protected</span> <span class="kt">virtual</span> <span class="k">function</span> <span class="kt">void</span> <span class="n">add_constraints</span><span class="p">();</span>
    <span class="n">only_legal_writes_constraint</span> <span class="n">c0</span> <span class="o">=</span> <span class="k">new</span><span class="p">();</span>
    <span class="n">only_mapped_addresses_constraint</span> <span class="n">c1</span> <span class="o">=</span> <span class="k">new</span><span class="p">();</span>
    <span class="n">constrained_sequence_item</span><span class="o">::</span><span class="n">add_global_constraint</span><span class="p">(</span><span class="n">c0</span><span class="p">);</span>
    <span class="n">constrained_sequence_item</span><span class="o">::</span><span class="n">add_global_constraint</span><span class="p">(</span><span class="n">c1</span><span class="p">);</span>
  <span class="k">endfunction</span>

  <span class="c1">// ...</span>
<span class="k">endclass</span>
</code></pre></div></div>

<p>We could also extend the test that only does legal writes and add the constraints for mapped addresses:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">class</span> <span class="n">test_legal_writes_to_mapped_addresses</span> <span class="k">extends</span> <span class="n">test_legal_writes</span><span class="p">;</span>

  <span class="k">protected</span> <span class="kt">virtual</span> <span class="k">function</span> <span class="kt">void</span> <span class="n">add_constraints</span><span class="p">();</span>
    <span class="n">only_mapped_addresses_constraint</span> <span class="n">c</span> <span class="o">=</span> <span class="k">new</span><span class="p">();</span>
    <span class="k">super</span><span class="p">.</span><span class="n">add_constraints</span><span class="p">();</span>
    <span class="n">constrained_sequence_item</span><span class="o">::</span><span class="n">add_global_constraint</span><span class="p">(</span><span class="n">c</span><span class="p">);</span>
  <span class="k">endfunction</span>

  <span class="c1">// ...</span>
<span class="k">endclass</span>
</code></pre></div></div>

<p>Of course, this approach can be used to handle all combinations of constraints.</p>

<p>Adding constraints dynamically has the same advantages as the mixin approach we looked at earlier.</p>

<p>It doesn’t suffer from the same readability issue, because we don’t rely on long parameterization chains. It suffers from a bit too much verboseness due to the multiple <em>add_global_constraint(…)</em> calls, though this could be improved by adding a variant of the function that accepts a list of constraint objects.</p>

<p>This approach also avoids the type explosion issue that mixins have and is potentially faster to compile.</p>

<p>There is a bit of boilerplate code required for the infrastructure. This can be extracted into a reusable library.</p>

<p>The first thing we need to do is to make the abstract constraint class parameterizable:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">virtual</span> <span class="kt">class</span> <span class="n">abstract_constraint</span> <span class="p">#(</span><span class="k">type</span> <span class="n">T</span> <span class="o">=</span> <span class="kt">int</span><span class="p">);</span>

  <span class="k">protected</span> <span class="n">T</span> <span class="n">object</span><span class="p">;</span>

  <span class="k">function</span> <span class="kt">void</span> <span class="n">set_object</span><span class="p">(</span><span class="n">T</span> <span class="n">object</span><span class="p">);</span>
    <span class="k">this</span><span class="p">.</span><span class="n">object</span> <span class="o">=</span> <span class="n">object</span><span class="p">;</span>
  <span class="k">endfunction</span>

<span class="k">endclass</span>
</code></pre></div></div>

<p>The package should expose a macro to handle the constraint infrastructure:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">`define</span> <span class="n">constraints_utils</span><span class="p">(</span><span class="n">TYPE</span><span class="p">)</span> \
  <span class="kt">static</span> <span class="k">function</span> <span class="kt">void</span> <span class="n">add_global_constraint</span><span class="p">(</span><span class="n">constraints</span><span class="o">::</span><span class="n">abstract_constraint</span> <span class="p">#(</span><span class="n">TYPE</span><span class="p">)</span> <span class="n">c</span><span class="p">);</span> \
  <span class="c1">// ...</span>
</code></pre></div></div>

<p>There was a subtle issue with the simplistic infrastructure code we looked at before. It wasn’t able to handle randomization of multiple instances at the same time (for example, when randomizing an array of sequence items). As this is a more exotic use case, the problem won’t show up immediately. It’s a simple fix to make, but it would be very annoying to have to make it in mutiple projects. Even when the code might look deceptively simple and have us think it’s not worth the hassle to put into an own library, doing so makes it easier to implement and propagate fixes for such issues.</p>

<p>The macro makes the definition of <em>constrained_sequence_item</em> much cleaner:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">class</span> <span class="n">constrained_sequence_item</span> <span class="k">extends</span> <span class="n">sequence_item</span><span class="p">;</span>

  <span class="cp">`constraints_utils</span><span class="p">(</span><span class="n">sequence_item</span><span class="p">)</span>

  <span class="c1">// ...</span>
<span class="k">endclass</span>
</code></pre></div></div>

<p>You can find the <a href="https://github.com/tudortimi/constraints">constraints</a> library on GitHub.</p>

<p>It already supports instance and global constraints. What I would like to add is the possibility to add constraints to all items under a UVM scope, similar to what the paper presents at the end, but using a nicer API that doesn’t require the user to do any UVM config DB calls.</p>

<p>I also want to look at the possibility of magically generating all test combinations, given a list of constraint objects. Currently we had to enumerate all combinations of constraints by writing a test class for each, which is very repetitive. It would be great if we could get this automatically and save ourselves the typing. This is something I’ll definitely look at in a future post.</p>

<p>In the meantime you can have a look at the <a href="https://github.com/verification-gentleman-blog/favor-composition-over-inheritance-even-for-constraints">full example code</a> on GitHub and try it out yourselves. I hope it inspires you to write flexible test suites that help you reach you verification goals faster.</p>]]></content><author><name>Tudor Timi</name></author><category term="SystemVerilog" /><category term="UVM" /><summary type="html"><![CDATA[Simulation is currently the dominant functional verification technique, with constrained random verification the most widely used methodology. While producing random data is a big part of it, letting the solver blindly generate stimulus isn’t going to be very efficient. Constraints are needed to guide the stimulus toward interesting scenarios.]]></summary></entry><entry><title type="html">Bigger Is Not Always Better: Builds Are Faster with Smaller Packages</title><link href="https://blog.verificationgentleman.com/2020/02/09/smaller-packages.html" rel="alternate" type="text/html" title="Bigger Is Not Always Better: Builds Are Faster with Smaller Packages" /><published>2020-02-09T19:44:00+01:00</published><updated>2020-02-09T19:44:00+01:00</updated><id>https://blog.verificationgentleman.com/2020/02/09/smaller-packages</id><content type="html" xml:base="https://blog.verificationgentleman.com/2020/02/09/smaller-packages.html"><![CDATA[<p>One trend over the past few years is that the projects I’ve been working on tend to get bigger and more complicated. Bigger projects come with new challenges. Among these are the fact that it’s much more difficult to keep the entire project in one’s head, the need to synchronize with more developers because team sizes grow, a higher risk of having to re-write code because of poorly understood requirements or because some requirements change, and many more.</p>

<p>There’s one thing, though, that crept up on me: compile times get much bigger. While this doesn’t sound like a big deal, I’ve found that long build times are an absolute drain on productivity. I use <a href="http://agilesoc.com/open-source-projects/svunit/">SVUnit</a> a lot, so I’m used to having a very short path between making a change and seeing the effects of that change. Ideally, there should be no delay between starting the test script and getting the result. A delay of a couple of seconds is tolerable. More than 10 seconds becomes noticeable. After exceeding the one minute mark, the temptation to switch to something else (like the Internet browser) becomes very high. This slowdown happens gradually, with each new class that is added, decreasing development speed.</p>

<p>In this post I’d like to talk about compilation. This topic has a tendency to be trivialized and underestimated, even more so in the hardware industry, where it’s common to have design flows already set up to deal with this process.</p>

<h2 id="full-vs-incremental-builds">Full vs. incremental builds</h2>

<p>A build is the process of taking the source code and producing an executable object. When talking about builds, there are two terms we need to be familiar with: full builds and incremental builds. A full build is performed when there isn’t any build output, which requires the entire source code to be built. This is either the case when starting in a new workspace (for example, after cloning the source repository) or after deleting the previous build output. An incremental build only builds the parts of the source code that have changed since the previous build. Because only parts of the project are rebuilt in this case, this means that, generally, the process is faster.</p>

<p>We’ll limit our discussion about builds to SystemVerilog packages, though the same concepts also apply to modules and interfaces.</p>

<p>Let’s say we have two packages, <em>package0</em> and <em>package1</em>, which we use in our verification environment:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// File: package0.sv</span>

<span class="k">package</span> <span class="n">package0</span><span class="p">;</span>

  <span class="kt">class</span> <span class="n">some_base_class</span><span class="p">;</span>
  <span class="k">endclass</span>

<span class="k">endpackage</span>
</code></pre></div></div>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// File: package1.sv</span>

<span class="k">package</span> <span class="n">package1</span><span class="p">;</span>

  <span class="k">import</span> <span class="n">package0</span><span class="o">::*</span><span class="p">;</span>

  <span class="kt">class</span> <span class="n">some_derived_class</span> <span class="k">extends</span> <span class="n">some_base_class</span><span class="p">;</span>
  <span class="k">endclass</span>

<span class="k">endpackage</span>
</code></pre></div></div>

<p>Compiling these two packages using an EDA tool is pretty straightforward:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>compiler package0.sv package1.sv
</code></pre></div></div>

<p>The very first time we run this command, the tool will parse the two source files and generate the data structures it uses to represent the compiler output. Since we didn’t have any build output when we ran the command, we were performing a full build.</p>

<p>If we add a new class to <em>package1</em> and run the compiler again, we will be performing an incremental build:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">package</span> <span class="n">package1</span><span class="p">;</span>

  <span class="k">import</span> <span class="n">package0</span><span class="o">::*</span><span class="p">;</span>

  <span class="kt">class</span> <span class="n">some_derived_class</span> <span class="k">extends</span> <span class="n">some_base_class</span><span class="p">;</span>
  <span class="k">endclass</span>

  <span class="kt">class</span> <span class="n">some_other_class</span><span class="p">;</span>
  <span class="k">endclass</span>

<span class="k">endpackage</span>
</code></pre></div></div>

<p>The tool will only recompile <em>package1</em>. It won’t touch <em>package0</em>, since it didn’t change. If compilation for <em>package0</em> takes a lot of time, this will saves us that time.</p>

<h2 id="a-deeper-dive-into-systemverilog-compilation">A deeper dive into SystemVerilog compilation</h2>

<p>Before we continue with our main discussion, it makes sense to look a bit deeper into how SystemVerilog compilation works. Before I investigated this topic I had some misplaced ideas, which I would like to dispel.</p>

<p>I have only ever really looked at the behavior of one particular EDA tool, but I assume that other simulators behave similarly, as they all have a common heritage. Some SystemVerilog tools differentiate between compilation and elaboration. These defintions depend on the tool you’re using. I’ve seen compilation used to mean parsing the code and generating syntax trees. Elaboration takes these syntax trees and generates executable code that is run in the simulator. I’ll use the term <em>compile</em> to mean both of these steps.</p>

<p>Let’s start small, with a single package that contains only one class:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">package</span> <span class="n">package0</span><span class="p">;</span>

  <span class="kt">class</span> <span class="n">some_base_class</span><span class="p">;</span>
  <span class="k">endclass</span>

<span class="k">endpackage</span>
</code></pre></div></div>

<p>After we compile the package, we will have performed a full build. Now, let’s add another class to the package:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">package</span> <span class="n">package0</span><span class="p">;</span>

  <span class="kt">class</span> <span class="n">some_base_class</span><span class="p">;</span>
  <span class="k">endclass</span>

  <span class="kt">class</span> <span class="n">some_base_class2</span><span class="p">;</span>
  <span class="k">endclass</span>

<span class="k">endpackage</span>
</code></pre></div></div>

<p>In this case, you’ll notice that the tool compiles both classes. I’m a bit cautious about posting the log files and how I can tell that it’s compiling both classes. Some tools make this easier to see than others. One clear sign is that compile takes longer. You can try it out by adding more and more classes and recompiling. I’ve created some scripts that can help out with such experiments: <a href="https://github.com/verification-gentleman-blog/smaller-packages/">https://github.com/verification-gentleman-blog/smaller-packages/</a>.</p>

<p>In this case, an incremental compile takes about as much time as a full build, which suggests that nothing is being reused from previous build attempts. Even if we only add classes, the build output for previously built classes is discarded.</p>

<p>What did we learn from this? That tools only organize build output using packages as their most granular unit. Changes within packages are “lost”, from an incremental build point of view.</p>

<p>You could argue that from the previous experiment we could infer that tools organize build output based on files. If we were to put each file in its own class and include them in the package, then the tool would be able to somehow behave differently. This isn’t, the case, though. <code class="language-plaintext highlighter-rouge">`include</code> directives are handled by the pre-processor. It interleaves all of the files together and gives the compiler a big file with all the class definitions inline (the situation we had previously).</p>

<p>We can do another experiment to convince ourselves that builds aren’t organized by files. Let’s put two packages inside the same file:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">package</span> <span class="n">package0</span><span class="p">;</span>
<span class="k">endpackage</span>

<span class="k">package</span> <span class="n">package1</span><span class="p">;</span>
<span class="k">endpackage</span>
</code></pre></div></div>

<p>Let’s modify <em>package1</em> by adding a new variable:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">package</span> <span class="n">package0</span><span class="p">;</span>
<span class="k">endpackage</span>

<span class="k">package</span> <span class="n">package1</span><span class="p">;</span>
  <span class="kt">bit</span> <span class="n">some_var</span><span class="p">;</span>
<span class="k">endpackage</span>
</code></pre></div></div>

<p>When rebuilding, we’ll notice that only <em>package1</em> gets rebuilt, but <em>package0</em> is left alone. (This is also the behavior we would have liked to have for classes inside a package.)</p>

<p>Now let’s also modify <em>package0</em> by adding a variable to it:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">package</span> <span class="n">package0</span><span class="p">;</span>
  <span class="kt">bit</span> <span class="n">some_var</span><span class="p">;</span>
<span class="k">endpackage</span>

<span class="k">package</span> <span class="n">package1</span><span class="p">;</span>
  <span class="kt">bit</span> <span class="n">some_var</span><span class="p">;</span>
<span class="k">endpackage</span>
</code></pre></div></div>

<p>When rebuilding, we’ll see that <em>package0</em> is being rebuilt, as we expected, but, surprisingly, so is <em>package1</em>. This is very confusing initially, but obvious once you know the explanation. Because we shifted the lines where <em>package1</em> and its items are defined in the file, the tool has to update debug information regarding line numbers. This is important for debuggers and for messages that contain line numbers (like assertion erros, <em>$info(…)</em> calls, etc.). This, by the way, is a very good reason to only define one element (package, interface, module) per file.</p>

<p>Let’s look at one more thing. Let’s take two packages that have a dependency relationship:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">package</span> <span class="n">package0</span><span class="p">;</span>

  <span class="kt">class</span> <span class="n">some_base_class</span><span class="p">;</span>
  <span class="k">endclass</span>

<span class="k">endpackage</span>
</code></pre></div></div>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">package</span> <span class="n">package1</span><span class="p">;</span>

  <span class="k">import</span> <span class="n">package0</span><span class="o">::*</span><span class="p">;</span>

  <span class="kt">class</span> <span class="n">some_derived_class</span> <span class="k">extends</span> <span class="n">some_base_class</span><span class="p">;</span>
  <span class="k">endclass</span>

<span class="k">endpackage</span>
</code></pre></div></div>

<p>It’s clear that changes to <em>package1</em> shouldn’t (and indeed won’t) cause rebuilds of <em>package0</em>. It’s also clear that changing <em>some_base_class</em> will have to trigger a rebuild of <em>package1</em>. Now, let’s add a new class to <em>package0</em>:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">package</span> <span class="n">package0</span><span class="p">;</span>

  <span class="kt">class</span> <span class="n">some_base_class</span><span class="p">;</span>
  <span class="k">endclass</span>

  <span class="kt">class</span> <span class="n">some_base_class2</span><span class="p">;</span>
  <span class="k">endclass</span>

<span class="k">endpackage</span>
</code></pre></div></div>

<p>At this point, we shouldn’t be surprised anymore that both packages are rebuilt in this case. This is because the tool only understands changes at the package level. <em>package1</em> depends on <em>package0</em>, so any change to <em>package0</em> will lead to a rebuild of <em>package1</em>, regardless if this is really needed. Unfortunately, this isn’t the behavior we would like to have.</p>

<p>Contrast the way SystemVerilog builds work to C++, where files are compiled individually and are linked together in a separate step (a gross over-simplifaction). Changes to one class don’t cause recompiles of other classes in the same namespace, if the two classes are unrelated. This is because C++ classes are split between the header (which declares which functions a class provides) and the implementation (which contain the function bodies). A class that depends on another class includes its header, to let the compiler know that it relies on the other class. Only changes in a class’s header cause recompiles of dependent classes, while changes to its implementation don’t. Because of this setup, C++ builds are much more powerful when it comes to build avoidance, by only rebuilding the parts that they absolutely have to build. This allows for guidelines that incremental builds should take between 5-10 seconds and that full builds (including tests) should take between 1-2 minutes, according to <a href="http://www.bitsnbites.eu/faster-c-builds/">http://www.bitsnbites.eu/faster-c-builds/</a>, numbers which are incredibly low by SystemVerilog standards, where merely starting the simulator takes double digit numbers of seconds.</p>

<h2 id="case-study">Case study</h2>

<p>The classic testbench structure for an IP block consists of one or more interface verification components (IVCs), that contain code related to the signal protocols used by the design, and one module verification component (MVC), that contains code for aspects related to the design functionality.</p>

<p>IVCs typically consist of a package and one or more interfaces. We don’t usually make changes to the IVCs, so once we’ve built them via a full build, they won’t have any impact on subsequent incremental builds.</p>

<p>Most of our work is focused on the MVC. As we’ve seen above, if we place our MVC code into one package, then any change we make to it will trigger a new build, because of the way SystemVerilog tools handle incremental builds. This isn’t going to be very efficient, as an incremental build of the package after each change will take about as long as a full build.</p>

<p>What would happen if we could split our big MVC package into multiple smaller packages?</p>

<p>It’s experiment time again! We’ll assume that we can split the code such that building each package takes the same amount of time. We’ll also ignore any extra costs from building multiple packages instead of one single package. This means that if an incremental build of the entire <em>mvc</em> package would have taken <em>N</em> seconds, then by splitting it into <em>P</em> packages each of the smaller packages would take <em>N/P</em> seconds to build. We’ll also assume that we are just as likely to make changes to any of the smaller packages. This means that the probablity to change any package is <em>1/P</em>.</p>

<p>Let’s assume that we can create two independent packages, <em>p0</em> and <em>p1</em>. We can misuse UML to visualize the package topology:</p>

<p><img src="https://yuml.me/diagram/plain;dir:TB/class/[p1],[p0]" alt="" /></p>

<p>Any change we make to <em>p0</em> won’t cause rebuilds of <em>p1</em> and vice-versa. We can compute the average incremental build time in this case. Building any of the packages takes <em>N/2</em> seconds, but we do it only half of the time (since in the other half we change the other package). The average incremental build time is the mean: <em>N/2 * 1/2 + N/2 * 1/2 = N/2</em>. By splitting the code into two independent packages, we’ve managed to half our incremental build time. It’s not very realistic, though, that we could manage to do such a split on a real project.</p>

<p>Let’s have a look at something closer to reality. Let’s assume that we can split our MVC into two packages, <em>p0</em> and <em>p1</em>, but <em>p1</em> depends on <em>p0</em>:</p>

<p><img src="https://yuml.me/diagram/plain;dir:TB/class/[p0]&lt;-[p1]" alt="" /></p>

<p>An incremental build of <em>p1</em> would still take only <em>N/2</em> seconds, because changing anything in <em>p1</em> doesn’t have any effect on <em>p0</em>. A change in <em>p0</em> would mean that we also have to rebuild <em>p1</em>, which means that it would take <em>N/2 + N/2 = N</em> seconds. On average, we would need <em>N/2 * 1/2 + N * 1/2 = 3/4 * N</em> seconds.</p>

<p>We should try to structure our code in such a way as to increase the number of packages without any dependencies to each other. Let’s say we can split <em>p1</em> from the previous example into two independent packages, <em>p1_0</em> and <em>p1_1</em>:</p>

<p><img src="https://yuml.me/diagram/plain;dir:TB/class/[p0]&lt;-[p1_1],[p0]&lt;-[p1_0]" alt="" /></p>

<p>In this case, changing anything in either <em>p1_0</em> or <em>p1_1</em> would take <em>N/3</em> seconds. A change in <em>p0</em> would require all three packages to be rebuilt and would take the full <em>N</em> seconds. On average, a change would take <em>N/3 * 1/3 + N/3 * 1/3 + N * 1/3 = 7/9 * N</em> seconds.</p>

<p>We could go on further with deeper package hierarchies, but I think you get the idea.</p>

<p>MVC code lends itself nicely to such a structure. We typically have some “common” code that models the basics of our DUT, from which we can model different higher level aspects, relating to the features of the DUT. We would use our models inside checks or coverage, which could be built independently from each other:</p>

<p><img src="https://yuml.me/diagram/plain;dir:TB/class/[base]&lt;-[model_aspect_C],[base]&lt;-[model_aspect_B],[base]&lt;-[model_aspect_A],[model_aspect_C]&lt;-[performance_checks],[model_aspect_B]&lt;-[functional_checks],[model_aspect_A]&lt;-[functional_checks],[model_aspect_A]&lt;-[coverage],[model_aspect_B]&lt;-[coverage],[model_aspect_C]&lt;-[coverage]" alt="" /></p>

<h2 id="conclusions">Conclusions</h2>

<p>Splitting code across multiple packages will generally be better for compilation speed. There are also other advantages. It could make the code base easier to understand, by grouping code by theme (code for <em>X</em> goes in package <em>p_x</em>, code for <em>Y</em> goes in package <em>p_y</em>). It could also make development easier, by allowing developers to specialize in only a handful of the packages, instead of having to deal with the entire code base.</p>

<p>Having to manage multiple packages brings its own set of challenges, though. It could make the code base more difficult to understand if the boundaries between packages are arbitrary (where does code for <em>X</em> go, in <em>p0</em> or <em>p1</em>?). More packages, especially when they have intricate dependency relationships, also make compilation more difficult to set up.</p>

<p>I’m not going to recommend making one package per class, just to improve build times. Ideally, SystemVerilog compilers should evolve to better handle incremental compilation, by working at levels lower than just packages. At the same time, you should care about turnaround time, so dumping all code into one package shouldn’t be your default mode of operation.</p>]]></content><author><name>Tudor Timi</name></author><category term="SystemVerilog" /><summary type="html"><![CDATA[One trend over the past few years is that the projects I’ve been working on tend to get bigger and more complicated. Bigger projects come with new challenges. Among these are the fact that it’s much more difficult to keep the entire project in one’s head, the need to synchronize with more developers because team sizes grow, a higher risk of having to re-write code because of poorly understood requirements or because some requirements change, and many more.]]></summary></entry><entry><title type="html">Testing SVA Properties and Sequences</title><link href="https://blog.verificationgentleman.com/2017/06/25/testing-sva-properties-and-sequences.html" rel="alternate" type="text/html" title="Testing SVA Properties and Sequences" /><published>2017-06-25T23:25:00+02:00</published><updated>2017-06-25T23:25:00+02:00</updated><id>https://blog.verificationgentleman.com/2017/06/25/testing-sva-properties-and-sequences</id><content type="html" xml:base="https://blog.verificationgentleman.com/2017/06/25/testing-sva-properties-and-sequences.html"><![CDATA[<p>After a pretty long absence, it’s finally time to complete the series on unit testing interface UVCs. I meant to write this post in October/November 2016. While writing the code, I got bogged down by a simulator bug and tried to find an elegant work around, but failed. I got frustrated and shelved the work for a while. In the meantime I got caught up with technical reading and with taking online courses. I’ve also been pretty busy at work, putting in quite a bit of overtime, which left without much energy to do anything blog related. Well, enough excuses, it’s time to get to it…</p>

<p>Aside from monitoring and driving signals, an interface UVC is also responsible for checking that the DUT conforms to the protocol specification. This is typically done with <em>SystemVerilog</em> assertions, which provide a compact and powerful syntax for describing temporal behavior at the signal level. I already wrote a bit about <a href="/2016/07/24/a-quick-look-at-svaunit.html">unit testing SVAs using SVAUnit</a>, a library from our friends at <a href="https://www.amiq.com/consulting/">AMIQ Consulting</a>.</p>

<p>I’ve since then had a bit of an epiphany while working on an interface UVC for a new proprietary on-chip interface. Now on a previous module, I needed to write some bigger SVA properties of the type “when register X is written via AHB, then Y happens”. The AHB UVC I was using (also written by me a while back) only had assertions embedded in a checker, but it didn’t export any SVA sequences for users to combine into their own properties. I ended up doing a bit of clipboard based inheritance and defining the needed sequences in my module SVA checker. I had a similar problem when I was trying to write some simple formal properties for a different module, where I also just copied (gasp!) and patched the needed code. Now AHB isn’t such a complicated and/or dynamic protocol, but my actions were in direct violation of the <a href="https://en.wikipedia.org/wiki/Don%27t_repeat_yourself">DRY princple</a>. For the new UVC I was developing, I decided to not make the same mistake and build a nice hierarchy of SVA sequences, properties and assertions. These would form part of the UVC API, sort of an SVA API which users could “call” in their own code. As any important parts of the exported API, such members have to be unit tested.</p>

<p>Let’s look at some simple AHB SVA constructs. Since this protocol is so popular, I assume that most of you are already aquainted with it and for those of you who aren’t I’ll try to keep things simple, but I won’t explain any protocol details. Since the spec isn’t open, I can’t link it here, but a quick search should net you some useful resources. Nevertheless, I’m pretty sure you’ll be able to follow the post without becoming an expert in the protocol.</p>

<p>One of the first non-trivial protocol rules for AHB is that “[when] the slave is requesting wait states, the master must not change the transfer type […]”. Let’s write a property for this with the following signature:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">property</span> <span class="n">trans_held_until_ready</span><span class="p">(</span><span class="n">HTRANS</span><span class="p">,</span> <span class="n">HREADY</span><span class="p">);</span>
  <span class="c1">// ...</span>
<span class="k">endproperty</span>
</code></pre></div></div>

<p>In the <a href="/2016/08/15/testing-uvm-drivers-part-2.html">previous post</a> we saw how we can use the <strong>expect</strong> statement to check that signal toggles happen as desired. The unit test supplied the property, while the code being tested handled the signals. To check a property, we can reverse the two roles and have the test supply the signal toggles, while the code under test is exactly our property of interest. The same <code class="language-plaintext highlighter-rouge">`FAIL_UNLESS_PROP(…)</code> macro can help us check if the property passes for a legal trace:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code>    <span class="cp">`SVTEST</span><span class="p">(</span><span class="n">trans_held_until_ready__trans_stable__passes</span><span class="p">)</span>
      <span class="n">cb</span><span class="p">.</span><span class="n">HTRANS</span> <span class="o">&lt;=</span> <span class="n">NONSEQ</span><span class="p">;</span>
      <span class="n">cb</span><span class="p">.</span><span class="n">HREADY</span> <span class="o">&lt;=</span> <span class="mi">0</span><span class="p">;</span>
      <span class="n">cb</span><span class="p">.</span><span class="n">HREADY</span> <span class="o">&lt;=</span> <span class="p">##</span><span class="mi">3</span> <span class="mi">1</span><span class="p">;</span>

      <span class="cp">`FAIL_UNLESS_PROP</span><span class="p">(</span><span class="n">trans_held_until_ready</span><span class="p">(</span><span class="n">HTRANS</span><span class="p">,</span> <span class="n">HREADY</span><span class="p">))</span>
    <span class="cp">`SVTEST_END</span>
</code></pre></div></div>

<p>I’ve ommited the definitions of the signals, which are bundled in a <strong>clocking block</strong> called <em>cb</em>. Declaring this clocking block as default also allows use to use the cycled delay operator, <em>##n</em>, which makes the code a bit more readable.</p>

<p>Just checking that properties pass is rather boring though. Not only that, but a property that doesn’t pass when it should results in a false negative, which is instantly visible in the simulation log. It’s much more valuable that a property fail when it should, because false positives are much more insidious and less likely to be caught. We can do this also with an <strong>expect</strong> statement, but we’ll need to trigger a fail if the corresponding pass block is triggered. As with <code class="language-plaintext highlighter-rouge">`FAIL_UNLESS_PROP(…)</code>, we can wrap this check inside a macro:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">`define</span> <span class="n">FAIL_IF_PROP_PASS</span><span class="p">(</span><span class="n">prop</span><span class="p">)</span> \
  <span class="k">expect</span> <span class="p">(</span><span class="n">prop</span><span class="p">)</span> \
    <span class="cp">`FAIL_IF</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
</code></pre></div></div>

<p>Having <em>HTRANS</em> change before an occurence of <em>HREADY</em> should cause our property to fail:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code>    <span class="cp">`SVTEST</span><span class="p">(</span><span class="n">trans_held_until_ready__trans_changes__fails</span><span class="p">)</span>
      <span class="n">cb</span><span class="p">.</span><span class="n">HTRANS</span> <span class="o">&lt;=</span> <span class="n">NONSEQ</span><span class="p">;</span>
      <span class="n">cb</span><span class="p">.</span><span class="n">HREADY</span> <span class="o">&lt;=</span> <span class="mi">0</span><span class="p">;</span>
      <span class="n">cb</span><span class="p">.</span><span class="n">HTRANS</span> <span class="o">&lt;=</span> <span class="p">##</span><span class="mi">3</span> <span class="n">SEQ</span><span class="p">;</span>

      <span class="cp">`FAIL_IF_PROP</span><span class="p">(</span><span class="n">trans_held_until_ready</span><span class="p">(</span><span class="n">HTRANS</span><span class="p">,</span> <span class="n">HREADY</span><span class="p">))</span>
    <span class="cp">`SVTEST_END</span>
</code></pre></div></div>

<p>Here’s how a property that satisfies both tests could look:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">property</span> <span class="n">trans_held_until_ready</span><span class="p">(</span><span class="n">HTRANS</span><span class="p">,</span> <span class="n">HREADY</span><span class="p">);</span>
  <span class="n">HTRANS</span> <span class="k">inside</span> <span class="o">{</span> <span class="n">NONSEQ</span><span class="p">,</span> <span class="n">SEQ</span> <span class="o">}</span> <span class="o">|=&gt;</span>
    <span class="p">$</span><span class="nb">stable</span><span class="p">(</span><span class="n">HTRANS</span><span class="p">)</span> <span class="k">throughout</span> <span class="n">HREADY</span> <span class="p">[</span><span class="o">-&gt;</span><span class="mi">1</span><span class="p">];</span>
<span class="k">endproperty</span>
</code></pre></div></div>

<p>Those of you who’ve worked with AHB before might raise an eyebrow looking at that code. What if, for example, <em>HTRANS</em> comes together with <em>HREADY</em> and changes in the following cycle? The property shouldn’t fail, as the first transfer was accepted and a new one can begin. We can add a test for this exact situation:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code>    <span class="cp">`SVTEST</span><span class="p">(</span><span class="n">trans_held_until_ready__trans_stable__passes</span><span class="p">)</span>
      <span class="n">cb</span><span class="p">.</span><span class="n">HTRANS</span> <span class="o">&lt;=</span> <span class="n">NONSEQ</span><span class="p">;</span>
      <span class="n">cb</span><span class="p">.</span><span class="n">HREADY</span> <span class="o">&lt;=</span> <span class="mi">0</span><span class="p">;</span>
      <span class="n">cb</span><span class="p">.</span><span class="n">HREADY</span> <span class="o">&lt;=</span> <span class="p">##</span><span class="mi">3</span> <span class="mi">1</span><span class="p">;</span>

      <span class="cp">`FAIL_UNLESS_PROP</span><span class="p">(</span><span class="n">trans_held_until_ready</span><span class="p">(</span><span class="n">HTRANS</span><span class="p">,</span> <span class="n">HREADY</span><span class="p">))</span>
    <span class="cp">`SVTEST_END</span>
</code></pre></div></div>

<p>With this test, we can fix the property:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="k">property</span> <span class="n">trans_held_until_ready</span><span class="p">(</span><span class="n">HTRANS</span><span class="p">,</span> <span class="n">HREADY</span><span class="p">);</span>
    <span class="n">HTRANS</span> <span class="k">inside</span> <span class="o">{</span> <span class="n">NONSEQ</span><span class="p">,</span> <span class="n">SEQ</span> <span class="o">}</span> <span class="o">|-&gt;</span>
      <span class="n">HREADY</span> <span class="kt">or</span> <span class="p">##</span><span class="mi">1</span> <span class="p">($</span><span class="nb">stable</span><span class="p">(</span><span class="n">HTRANS</span><span class="p">)</span> <span class="k">throughout</span> <span class="n">HREADY</span> <span class="p">[</span><span class="o">-&gt;</span><span class="mi">1</span><span class="p">]);</span>
  <span class="k">endproperty</span>
</code></pre></div></div>

<p>Some of you might argue that when <em>HTRANS</em> comes at the same time as <em>HREADY</em>, we’re not really “holding” anything. It could be argued that this is a special case and what we’re really interested in for this property are the cases where we actually see some wait states. We could exclude the instant grant case by tweaking the antecedent in such a way that it doesn’t match. This would lead to a vacuous pass of the property. A vacuous pass means that we have’t really checked anything, because we didn’t particularly care what happened in that situation. Vacuous passes aren’t usually shown in the assertion statistics, so we could “misuse” the number of times an assertion of this property passes as coverage for how many times we’ve seen (correctly) stalled transfers.</p>

<p>A vacuous pass is still a pass though and as per the LRM it should also trigger the execution of an <strong>assert</strong>/<strong>expect</strong> statement’s pass block. Some tools don’t work like this, though, choosing instead to not execute pass blocks on vacuous successes (unless the user explictly enables this, maybe via some command line switch or simulator setting). We can use this to our advantage to distinguish between a “real” pass and a vacuous pass. What we have then, is a sort of ternary logic, where a property can result in one of the following:</p>

<ul>
  <li>(nonvacuous) pass, where the pass block is executed</li>
  <li>fail, where the fail block is executed</li>
  <li>vacuous pass, where neither block is executed</li>
</ul>

<p>Note that there’s no concept of vacuous fails. Something either works, it doesn’t or it isn’t “important”.</p>

<p>Even if a simulator does execute pass block for vacuous successes, this behavior can either be turned off via a switch or, in a more portable fashion, via the <em>$assertcontrol(…)</em> system task (if it’s supported by the tool). This means that we can rather safely rely on the behavior described in the outcome list to determine vacuity.</p>

<p>As before, we can wrap such a check inside a macro. It’s definition is a bit trickier, since we need to check that neither block was executed. We can do this using variables:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">`define</span> <span class="n">FAIL_UNLESS_PROP_VAC</span><span class="p">(</span><span class="n">prop</span><span class="p">)</span> \
  <span class="k">begin</span> \
    <span class="kt">bit</span> <span class="n">pass_called</span><span class="p">;</span> \
    <span class="kt">bit</span> <span class="n">fail_called</span><span class="p">;</span> \
    \
    <span class="k">expect</span> <span class="p">(</span><span class="n">prop</span><span class="p">)</span> \
      <span class="n">pass_called</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> \
    <span class="k">else</span> \
      <span class="n">fail_called</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> \
    \
    <span class="k">if</span> <span class="p">(</span><span class="n">pass_called</span> <span class="o">||</span> <span class="n">fail_called</span><span class="p">)</span> \
      <span class="cp">`FAIL_IF</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> \
  <span class="k">end</span>
</code></pre></div></div>

<p>If any of the two blocks gets executed, one of the variables will be set and we can issue an error. This code, while deceptively simple, fails to compile in some simulators, with them complaining that they can’t find the definition of <em>pass_called</em> inside the pass block (and, of course, the same for <em>fail_called</em>). This is the part where I got bogged down trying to find a suitable workaround. The only way I could get this to work was to define the <em>*_called</em> variables inside a package and use the scope operator to reference them in the pass/fail blocks:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">package</span> <span class="n">vgm_svunit_utils_sva</span><span class="p">;</span>

  <span class="kt">bit</span> <span class="n">pass_called</span><span class="p">;</span>
  <span class="kt">bit</span> <span class="n">fail_called</span><span class="p">;</span>

<span class="k">endpackage</span>
</code></pre></div></div>

<p>This seems rather crazy, because not only does it require a user to include the file with the macro definition, but to also compile the extra support package. It’s a bit much for just a couple of measly variables, but it’s either this or nothing…</p>

<p>Since we’re going to rely on global variables with a persistent lifetime, we’ll need to make sure to set them to <em>0</em> before executing the <strong>expect</strong>:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">`define</span> <span class="n">FAIL_UNLESS_PROP_VAC</span><span class="p">(</span><span class="n">prop</span><span class="p">)</span> \
  <span class="k">begin</span> \
    <span class="n">vgm_svunit_utils_sva</span><span class="o">::</span><span class="n">pass_called</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> \
    <span class="n">vgm_svunit_utils_sva</span><span class="o">::</span><span class="n">fail_called</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> \
    \
    <span class="k">expect</span> <span class="p">(</span><span class="n">prop</span><span class="p">)</span> \
      <span class="n">vgm_svunit_utils_sva</span><span class="o">::</span><span class="n">pass_called</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> \
    <span class="k">else</span> \
      <span class="n">vgm_svunit_utils_sva</span><span class="o">::</span><span class="n">fail_called</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> \
    \
    <span class="k">if</span> <span class="p">(</span><span class="n">vgm_svunit_utils_sva</span><span class="o">::</span><span class="n">pass_called</span> <span class="o">||</span> \
        <span class="n">vgm_svunit_utils_sva</span><span class="o">::</span><span class="n">fail_called</span><span class="p">)</span> \
      <span class="cp">`FAIL_IF</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> \
  <span class="k">end</span>
</code></pre></div></div>

<p>Using this macro, we can tweak our test for instantly granted transfers to require a vacuous pass for the property:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code>    <span class="cp">`SVTEST</span><span class="p">(</span><span class="n">trans_held_until_ready__trans_stable__vacuous</span><span class="p">)</span>
      <span class="n">cb</span><span class="p">.</span><span class="n">HTRANS</span> <span class="o">&lt;=</span> <span class="n">NONSEQ</span><span class="p">;</span>
      <span class="n">cb</span><span class="p">.</span><span class="n">HREADY</span> <span class="o">&lt;=</span> <span class="mi">0</span><span class="p">;</span>
      <span class="n">cb</span><span class="p">.</span><span class="n">HREADY</span> <span class="o">&lt;=</span> <span class="p">##</span><span class="mi">3</span> <span class="mi">1</span><span class="p">;</span>

      <span class="cp">`FAIL_UNLESS_PROP_VAC</span><span class="p">(</span><span class="n">trans_held_until_ready</span><span class="p">(</span><span class="n">HTRANS</span><span class="p">,</span> <span class="n">HREADY</span><span class="p">))</span>
    <span class="cp">`SVTEST_END</span>
</code></pre></div></div>

<p>This will also mean that we have to fix the property:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">property</span> <span class="n">trans_held_until_ready</span><span class="p">(</span><span class="n">HTRANS</span><span class="p">,</span> <span class="n">HREADY</span><span class="p">);</span>
  <span class="n">HTRANS</span> <span class="k">inside</span> <span class="o">{</span> <span class="n">NONSEQ</span><span class="p">,</span> <span class="n">SEQ</span> <span class="o">}</span> <span class="o">&amp;&amp;</span> <span class="o">!</span><span class="n">HREADY</span> <span class="o">|=&gt;</span>
    <span class="p">$</span><span class="nb">stable</span><span class="p">(</span><span class="n">HTRANS</span><span class="p">)</span> <span class="k">throughout</span> <span class="n">HREADY</span> <span class="p">[</span><span class="o">-&gt;</span><span class="mi">1</span><span class="p">];</span>
<span class="k">endproperty</span>
</code></pre></div></div>

<p>Let’s take a step back now. Remember, that for the <code class="language-plaintext highlighter-rouge">`FAIL_IF_PROP(…)</code> macro we were checking whether the pass block is executed and if it was we issued an error. This doesn’t fit into the whole “ternary logic” scheme we discussed above when talking about vacuity. If we only did this, we wouldn’t be able to distinguish a fail from a vacuous pass. The macro name is also kind of misleading. What do we want here? Do we want the property to fail? Do we want it to fail or be vacuous, but under no circumstances result in a nonvacuous pass? What I intended was the former, but others could just as well interpret it as the latter.</p>

<p>More explicit macros would better clarify our intent. In this case, what we want is a <code class="language-plaintext highlighter-rouge">`FAIL_UNLESS_PROP_FAIL(…)</code> macro, because we are explicitly checking that the property can catch errors. What we should check is that the fail block gets executed:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">`define</span> <span class="n">FAIL_UNLESS_PROP_FAIL</span><span class="p">(</span><span class="n">prop</span><span class="p">)</span> \
  <span class="k">begin</span> \
    <span class="n">vgm_svunit_utils_sva</span><span class="o">::</span><span class="n">fail_called</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> \
    \
    <span class="k">expect</span> <span class="p">(</span><span class="n">prop</span><span class="p">)</span> \
    <span class="k">else</span> \
      <span class="n">vgm_svunit_utils_sva</span><span class="o">::</span><span class="n">fail_called</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> \
    \
    <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">vgm_svunit_utils_sva</span><span class="o">::</span><span class="n">fail_called</span><span class="p">)</span> \
      <span class="cp">`FAIL_IF</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> \
  <span class="k">end</span>
</code></pre></div></div>

<p>In some cases, we would want to forbid a property to fail, but it wouldn’t be important if the pass is vacuous or not. Here we would have a <code class="language-plaintext highlighter-rouge">`FAIL_IF_PROP_FAIL(…)</code> macro, that check that the fail block wasn’t executed. There are six such macros that we can define, a pair for each of the three possible outcomes. We won’t look at their definitions here, but their construction is pretty simple now that we know the behavior of the pass/fail blocks.</p>

<p>It’s time for another realization about our property: the trigger condition is slightly off. Once we assert it what’s going to happen is that a new evaluation thread is going to be started on each clock cycle where a transfer is stalled. All of these threads are going to run in parallel, perform the same check and end at the very same time – when <em>HREADY</em> finally comes. This isn’t good for perfomance, especially if we have many AHB interfaces and very long stalls.</p>

<p>The start of an AHB transaction is a pretty interesting event, not only for this property, but potentially for others. A UVC user might be interesed in writing an own property that triggers once a transfer has started. We can fix our property and at the same time provide a reusable building block by defining a <strong>sequence</strong>:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">sequence</span> <span class="n">trans_started</span><span class="p">(</span><span class="n">HTRANS</span><span class="p">);</span>
  <span class="c1">// ...</span>
<span class="k">endsequence</span>
</code></pre></div></div>

<p>Just as for properties we wanted to check whether they fail or pass when we want them, for sequence we want to make sure that they match when they should and don’t match when they shouldn’t. We can check for a sequence match (or lack thereof) by treating it as a property and checking its pass/fail state. Doing the following would look a bit weird, though:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">`FAIL_UNLESS_PROP_PASS</span><span class="p">(</span><span class="n">trans_started</span><span class="p">(</span><span class="n">HTRANS</span><span class="p">))</span>
</code></pre></div></div>

<p>The intent of the code becomes a bit muddied: “Are we testing a property? But I thought <em>trans_started(…)</em> was a sequence…”. It would be better to have separate macros for sequence testing:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">`define</span> <span class="n">FAIL_IF_SEQ</span><span class="p">(</span><span class="n">seq</span><span class="p">)</span> \
  <span class="cp">`FAIL_UNLESS_PROP_FAIL</span><span class="p">(</span><span class="n">seq</span> <span class="p">##</span><span class="mi">0</span> <span class="mi">1</span><span class="p">)</span>

<span class="cp">`define</span> FAIL_UNLESS_SEQ<span class="err">(</span>seq<span class="err">)</span> \
  <span class="err">`</span>FAIL_UNLESS_PROP_PASS<span class="err">(</span>seq <span class="err">##</span>0 1<span class="err">)</span><span class="cp">
</span></code></pre></div></div>

<p>Using these will make the code a bit clearer. Also, notice the extra <em>##0 1</em> fused after the sequence. This is to ensure that we can’t accidentally pass a property as an argument, because the fusion operator will cause a compile error unless what comes before it is a <strong>sequence</strong>.</p>

<p>Coming back to our <em>trans_started(…)</em> sequence, the first thing we would like it to do is to not match when <em>HTRANS</em> is <em>IDLE</em>:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code>    <span class="cp">`SVTEST</span><span class="p">(</span><span class="n">trans_started__idle__doesnt_match</span><span class="p">)</span>
      <span class="n">HTRANS</span> <span class="o">&lt;=</span> <span class="n">IDLE</span><span class="p">;</span>
      <span class="cp">`FAIL_IF_SEQ</span><span class="p">(</span><span class="n">trans_started</span><span class="p">(</span><span class="n">HTRANS</span><span class="p">))</span>
    <span class="cp">`SVTEST_END</span>
</code></pre></div></div>

<p>We would also like it to match then <em>HTRANS</em> becomes active after an <em>IDLE</em>:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code>    <span class="cp">`SVTEST</span><span class="p">(</span><span class="n">trans_started__coming_from_idle__matches</span><span class="p">)</span>
      <span class="n">cb</span><span class="p">.</span><span class="n">HTRANS</span> <span class="o">&lt;=</span> <span class="n">IDLE</span><span class="p">;</span>
      <span class="p">##</span><span class="mi">1</span><span class="p">;</span>

      <span class="n">cb</span><span class="p">.</span><span class="n">HTRANS</span> <span class="o">&lt;=</span> <span class="n">NONSEQ</span><span class="p">;</span>

      <span class="cp">`FAIL_UNLESS_SEQ</span><span class="p">(</span><span class="n">trans_started</span><span class="p">(</span><span class="n">HTRANS</span><span class="p">))</span>
    <span class="cp">`SVTEST_END</span>
</code></pre></div></div>

<p>With our tests in place, we can write the sequence implementation that fulfils them:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">sequence</span> <span class="n">trans_started</span><span class="p">(</span><span class="n">HTRANS</span><span class="p">);</span>
  <span class="n">HTRANS</span> <span class="k">inside</span> <span class="o">{</span> <span class="n">NONSEQ</span><span class="p">,</span> <span class="n">SEQ</span> <span class="o">}</span> <span class="o">&amp;&amp;</span>
    <span class="p">$</span><span class="nb">past</span><span class="p">(</span><span class="n">HTRANS</span> <span class="k">inside</span> <span class="o">{</span> <span class="n">IDLE</span><span class="p">,</span> <span class="n">BUSY</span> <span class="o">}</span><span class="p">);</span>
<span class="k">endsequence</span>
</code></pre></div></div>

<p>Something still doesn’t feel right, though. What about back to back transfers? It’s perfectly legal to start a new transfer immediately after the previous one was granted. In this case, there isn’t any <em>IDLE</em> cycle to use as an anchor. What we can, however, use is the occurrence of <em>HREADY</em> in the previous cycle, which we’ll have to feed to the property. Here’s how this could be tested:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code>    <span class="cp">`SVTEST</span><span class="p">(</span><span class="n">trans_started__after_done_trans__matches</span><span class="p">)</span>
      <span class="n">cb</span><span class="p">.</span><span class="n">HTRANS</span> <span class="o">&lt;=</span> <span class="n">NONSEQ</span><span class="p">;</span>
      <span class="n">cb</span><span class="p">.</span><span class="n">HREADY</span> <span class="o">&lt;=</span> <span class="mi">1</span><span class="p">;</span>
      <span class="p">##</span><span class="mi">1</span><span class="p">;</span>

      <span class="cp">`FAIL_UNLESS_SEQ</span><span class="p">(</span><span class="n">trans_started</span><span class="p">(</span><span class="n">HTRANS</span><span class="p">,</span> <span class="n">HREADY</span><span class="p">))</span>
    <span class="cp">`SVTEST_END</span>
</code></pre></div></div>

<p>The fixed sequence would then be:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">sequence</span> <span class="n">trans_started</span><span class="p">(</span><span class="n">HTRANS</span><span class="p">,</span> <span class="n">HREADY</span><span class="p">);</span>
  <span class="n">HTRANS</span> <span class="k">inside</span> <span class="o">{</span> <span class="n">NONSEQ</span><span class="p">,</span> <span class="n">SEQ</span> <span class="o">}</span> <span class="o">&amp;&amp;</span>
    <span class="p">$</span><span class="nb">past</span><span class="p">(</span><span class="n">HTRANS</span> <span class="k">inside</span> <span class="o">{</span> <span class="n">IDLE</span><span class="p">,</span> <span class="n">BUSY</span> <span class="o">}</span> <span class="o">||</span> <span class="n">HREADY</span><span class="p">);</span>
<span class="k">endsequence</span>
</code></pre></div></div>

<p>If we try to run this in the simulator, though, the test is still going to fail, even though there isn’t anything obviously wrong with our fix. This is because the test contains a very subtle mistake. When the underlying <strong>expect</strong> statement from the <code class="language-plaintext highlighter-rouge">`FAIL_*(…)</code> macro kicks in, in its very first cycle the value returned by <em>$past(HREADY)</em> is <em>0</em>, because we haven’t actually let it run long enough for there to have been an actual previous cycle. The LRM states that in this case <em>$past(…)</em> returns the default value of the expression passed to it. What we need to do is move the delay operator into the <code class="language-plaintext highlighter-rouge">`FAIL_*(…)</code> macro, to allow the <strong>expect</strong> to sample <em>HREADY</em> first and look for a match of <em>trans_started(…)</em> afterwards:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code>    <span class="cp">`SVTEST</span><span class="p">(</span><span class="n">trans_started__after_done_trans__matches</span><span class="p">)</span>
      <span class="n">cb</span><span class="p">.</span><span class="n">HTRANS</span> <span class="o">&lt;=</span> <span class="n">NONSEQ</span><span class="p">;</span>
      <span class="n">cb</span><span class="p">.</span><span class="n">HREADY</span> <span class="o">&lt;=</span> <span class="mi">1</span><span class="p">;</span>

      <span class="cp">`FAIL_UNLESS_SEQ</span><span class="p">(##</span><span class="mi">1</span> <span class="n">trans_started</span><span class="p">(</span><span class="n">HTRANS</span><span class="p">,</span> <span class="n">HREADY</span><span class="p">))</span>
    <span class="cp">`SVTEST_END</span>
</code></pre></div></div>

<p>This way the test does what we intend it to do. We can now instantiate the sequence inside our <em>trans_held_until_ready(…)</em> property to have it trigger at the appropriate times. Since <em>trans_started(…)</em> has already been tested, we don’t have to write too many tests for the property, focusing just on what’s important. Also, by breaking the problem into smaller parts its easier to notice what the corner cases might be. As we’ve seen, writing even such a small property can be tricky, so we should make sure that our code works before trusting it to find design bugs.</p>

<p>Regarding the testing of assertions, I’m not saying that this isn’t important as well. A lot of the more complicated assertions we need to write will have to rely on support code (for example when pipelining comes into the mix) and we’re going to want to check that all parts of an assertion – the property, the support code and the connections between them – fit properly together. For protocol assertions and other simple assertions, I favor breaking down into smaller properties and sequences and testing those, not only to make testing easier, but to also provide a set of reusable elements that UVC users can integrate into their own code.</p>

<p>You can find the full code for the examples <a href="https://github.com/verification-gentleman-blog/testing_seqs_and_props">here</a> and you can also download the <a href="https://github.com/tudortimi/vgm_svunit_utils">SVUnit utils package</a> if you want to start using these techiques for your own code.</p>

<p>There’s still some work to be done regarding unit tests and SVA constructs. For one, we strongly relied on the assumption that vacuous passes don’t trigger action blocks. We could add some code that tests this assumption by doing a trial run of a known vacuous property (e.g. <em>0 -&gt; 1</em>). If this isn’t the case, we could try calling the <em>$assertcontrol(…)</em> system task to disable vacuous success execution of pass blocks, if the task is available. Finally, if all else fails, we could inform the user to change the tool invocation to match our required behavior. This plan makes me feel less bad about the extra <em>*_utils_sva</em> package, which we had to use for the workaround with the status variables, because this is where we’d put all of this extra code. I’d also like to see this code merged into SVUnit at some point, but I’m not sure if now is the right time, due to the differences in tool capabilities across simulator vendors.</p>

<p>Now I’d like to conclude this series on unit testing UVCs. The tips in the past few posts should help you develop your UVCs faster and with higher quality, thereby increasing your confidence that they are ready for life in the harsh and unforgiving world of verification.</p>]]></content><author><name>Tudor Timi</name></author><category term="ABV" /><category term="Assertion Based Verification" /><category term="SVUnit" /><category term="SystemVerilog" /><category term="Unit testing" /><summary type="html"><![CDATA[After a pretty long absence, it’s finally time to complete the series on unit testing interface UVCs. I meant to write this post in October/November 2016. While writing the code, I got bogged down by a simulator bug and tried to find an elegant work around, but failed. I got frustrated and shelved the work for a while. In the meantime I got caught up with technical reading and with taking online courses. I’ve also been pretty busy at work, putting in quite a bit of overtime, which left without much energy to do anything blog related. Well, enough excuses, it’s time to get to it…]]></summary></entry><entry><title type="html">Testing UVM Drivers, Part 2</title><link href="https://blog.verificationgentleman.com/2016/08/15/testing-uvm-drivers-part-2.html" rel="alternate" type="text/html" title="Testing UVM Drivers, Part 2" /><published>2016-08-15T16:30:00+02:00</published><updated>2016-08-15T16:30:00+02:00</updated><id>https://blog.verificationgentleman.com/2016/08/15/testing-uvm-drivers-part-2</id><content type="html" xml:base="https://blog.verificationgentleman.com/2016/08/15/testing-uvm-drivers-part-2.html"><![CDATA[<p>In the <a href="/2016/08/07/testing-uvm-drivers.html">previous post</a> we looked at how we can emulate sequencer/driver communication using a lightweight stub of <em>uvm_sequencer</em>. Let’s also look at some more tips and tricks I’ve picked up while writing unit tests for drivers. To mix things up a bit, let’s look at the AXI protocol. We’re not going to implement a full featured driver; instead, we’ll focus on the write channels:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">interface</span> <span class="n">vgm_axi_interface</span><span class="p">(</span><span class="kt">input</span> <span class="kt">bit</span> <span class="n">ACLK</span><span class="p">,</span> <span class="kt">input</span> <span class="kt">bit</span> <span class="n">ARESETn</span><span class="p">);</span>
  <span class="kt">logic</span> <span class="p">[</span><span class="mi">3</span><span class="o">:</span><span class="mi">0</span><span class="p">]</span> <span class="n">AWID</span><span class="p">;</span>
  <span class="kt">logic</span> <span class="p">[</span><span class="mi">31</span><span class="o">:</span><span class="mi">0</span><span class="p">]</span> <span class="n">AWADDR</span><span class="p">;</span>
  <span class="kt">logic</span> <span class="p">[</span><span class="mi">3</span><span class="o">:</span><span class="mi">0</span><span class="p">]</span> <span class="n">AWLEN</span><span class="p">;</span>
  <span class="kt">logic</span> <span class="n">AWVALID</span><span class="p">;</span>
  <span class="kt">logic</span> <span class="n">AWREADY</span><span class="p">;</span>

  <span class="kt">logic</span> <span class="p">[</span><span class="mi">3</span><span class="o">:</span><span class="mi">0</span><span class="p">]</span> <span class="n">WID</span><span class="p">;</span>
  <span class="kt">logic</span> <span class="p">[</span><span class="mi">31</span><span class="o">:</span><span class="mi">0</span><span class="p">]</span> <span class="n">WDATA</span><span class="p">;</span>
  <span class="kt">logic</span> <span class="n">WLAST</span><span class="p">;</span>
  <span class="kt">logic</span> <span class="n">WVALID</span><span class="p">;</span>
  <span class="kt">logic</span> <span class="n">WREADY</span><span class="p">;</span>

  <span class="kt">logic</span> <span class="p">[</span><span class="mi">3</span><span class="o">:</span><span class="mi">0</span><span class="p">]</span> <span class="n">BID</span><span class="p">;</span>
  <span class="kt">logic</span> <span class="p">[</span><span class="mi">1</span><span class="o">:</span><span class="mi">0</span><span class="p">]</span> <span class="n">BRESP</span><span class="p">;</span>
  <span class="kt">logic</span> <span class="n">BVALID</span><span class="p">;</span>
  <span class="kt">logic</span> <span class="n">BREADY</span><span class="p">;</span>
<span class="k">endinterface</span>
</code></pre></div></div>

<p>Our sequence item will model the properties of a write transaction:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">typedef</span> <span class="kt">enum</span> <span class="kt">bit</span> <span class="p">[</span><span class="mi">3</span><span class="o">:</span><span class="mi">0</span><span class="p">]</span> <span class="o">{</span> <span class="n">LENGTH_</span><span class="p">[</span><span class="mi">1</span><span class="o">:</span><span class="mi">16</span><span class="p">]</span> <span class="o">}</span> <span class="n">length_e</span><span class="p">;</span>


<span class="kt">class</span> <span class="n">sequence_item</span> <span class="k">extends</span> <span class="n">uvm_sequence_item</span><span class="p">;</span>
  <span class="k">rand</span> <span class="kt">bit</span> <span class="p">[</span><span class="mi">3</span><span class="o">:</span><span class="mi">0</span><span class="p">]</span> <span class="n">id</span><span class="p">;</span>
  <span class="k">rand</span> <span class="kt">bit</span> <span class="p">[</span><span class="mi">31</span><span class="o">:</span><span class="mi">0</span><span class="p">]</span> <span class="n">address</span><span class="p">;</span>
  <span class="k">rand</span> <span class="n">length_e</span> <span class="n">length</span><span class="p">;</span>
  <span class="k">rand</span> <span class="n">transfer</span> <span class="n">transfers</span><span class="p">[];</span>
  <span class="k">rand</span> <span class="kt">int</span> <span class="kt">unsigned</span> <span class="n">delay</span><span class="p">;</span>

  <span class="c1">// ...</span>
<span class="k">endclass</span>


<span class="kt">class</span> <span class="n">transfer</span> <span class="k">extends</span> <span class="n">uvm_sequence_item</span><span class="p">;</span>
  <span class="k">rand</span> <span class="kt">bit</span><span class="p">[</span><span class="mi">31</span><span class="o">:</span><span class="mi">0</span><span class="p">]</span> <span class="n">data</span><span class="p">;</span>
  <span class="k">rand</span> <span class="kt">int</span> <span class="kt">unsigned</span> <span class="n">delay</span><span class="p">;</span>

  <span class="c1">// ...</span>
<span class="k">endclass</span>
</code></pre></div></div>

<p>The driver will consist of the familiar get and drive loop:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">class</span> <span class="n">master_driver</span> <span class="k">extends</span> <span class="n">uvm_driver</span> <span class="p">#(</span><span class="n">sequence_item</span><span class="p">);</span>
  <span class="kt">virtual</span> <span class="n">vgm_axi_interface</span> <span class="n">intf</span><span class="p">;</span>

  <span class="kt">virtual</span> <span class="k">protected</span> <span class="k">task</span> <span class="n">get_and_drive</span><span class="p">();</span>
    <span class="k">forever</span> <span class="k">begin</span>
      <span class="n">seq_item_port</span><span class="p">.</span><span class="n">get_next_item</span><span class="p">(</span><span class="n">req</span><span class="p">);</span>
      <span class="n">drive</span><span class="p">();</span>
      <span class="n">seq_item_port</span><span class="p">.</span><span class="n">item_done</span><span class="p">();</span>
    <span class="k">end</span>
  <span class="k">endtask</span>

  <span class="c1">// ...</span>
<span class="k">endclass</span>
</code></pre></div></div>

<p>We’ll implement the driver based on the following unit tests. Have a quick look at them before going further:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code>    <span class="cp">`SVTEST</span><span class="p">(</span><span class="n">drive_awvalid__with_delay</span><span class="p">)</span>
      <span class="n">sequence_item</span> <span class="n">item</span> <span class="o">=</span> <span class="k">new</span><span class="p">(</span><span class="s">"item"</span><span class="p">);</span>
      <span class="cp">`FAIL_UNLESS</span><span class="p">(</span><span class="n">item</span><span class="p">.</span><span class="n">randomize</span><span class="p">()</span> <span class="k">with</span> <span class="o">{</span>
        <span class="n">delay</span> <span class="o">==</span> <span class="mi">3</span><span class="p">;</span>
      <span class="o">}</span><span class="p">)</span>
      <span class="n">sequencer</span><span class="p">.</span><span class="n">add_item</span><span class="p">(</span><span class="n">item</span><span class="p">);</span>

      <span class="kt">repeat</span> <span class="p">(</span><span class="mi">3</span><span class="p">)</span>
        <span class="o">@</span><span class="p">(</span><span class="kt">posedge</span> <span class="n">clk</span><span class="p">)</span> <span class="cp">`FAIL_UNLESS</span><span class="p">(</span><span class="n">intf</span><span class="p">.</span><span class="n">AWVALID</span> <span class="o">===</span> <span class="mi">0</span><span class="p">)</span>
      <span class="o">@</span><span class="p">(</span><span class="kt">posedge</span> <span class="n">clk</span><span class="p">)</span> <span class="cp">`FAIL_UNLESS</span><span class="p">(</span><span class="n">intf</span><span class="p">.</span><span class="n">AWVALID</span> <span class="o">===</span> <span class="mi">1</span><span class="p">)</span>
    <span class="cp">`SVTEST_END</span>


    <span class="cp">`SVTEST</span><span class="p">(</span><span class="n">drive_awvalid__held_until_hready</span><span class="p">)</span>
      <span class="n">sequence_item</span> <span class="n">item</span> <span class="o">=</span> <span class="k">new</span><span class="p">(</span><span class="s">"item"</span><span class="p">);</span>
      <span class="cp">`FAIL_UNLESS</span><span class="p">(</span><span class="n">item</span><span class="p">.</span><span class="n">randomize</span><span class="p">()</span> <span class="k">with</span> <span class="o">{</span>
        <span class="n">delay</span> <span class="o">==</span> <span class="mi">0</span><span class="p">;</span>
      <span class="o">}</span><span class="p">)</span>
      <span class="n">sequencer</span><span class="p">.</span><span class="n">add_item</span><span class="p">(</span><span class="n">item</span><span class="p">);</span>
      <span class="n">intf</span><span class="p">.</span><span class="n">AWREADY</span> <span class="o">&lt;=</span> <span class="mi">0</span><span class="p">;</span>

      <span class="kt">repeat</span> <span class="p">(</span><span class="mi">4</span><span class="p">)</span>
        <span class="o">@</span><span class="p">(</span><span class="kt">posedge</span> <span class="n">clk</span><span class="p">)</span> <span class="cp">`FAIL_UNLESS</span><span class="p">(</span><span class="n">intf</span><span class="p">.</span><span class="n">AWVALID</span> <span class="o">===</span> <span class="mi">1</span><span class="p">)</span>

      <span class="n">intf</span><span class="p">.</span><span class="n">AWREADY</span> <span class="o">&lt;=</span> <span class="mi">1</span><span class="p">;</span>
      <span class="o">@</span><span class="p">(</span><span class="kt">posedge</span> <span class="n">clk</span><span class="p">)</span> <span class="cp">`FAIL_UNLESS</span><span class="p">(</span><span class="n">intf</span><span class="p">.</span><span class="n">AWVALID</span> <span class="o">===</span> <span class="mi">1</span><span class="p">)</span>
      <span class="o">@</span><span class="p">(</span><span class="kt">posedge</span> <span class="n">clk</span><span class="p">)</span> <span class="cp">`FAIL_UNLESS</span><span class="p">(</span><span class="n">intf</span><span class="p">.</span><span class="n">AWVALID</span> <span class="o">===</span> <span class="mi">0</span><span class="p">)</span>
    <span class="cp">`SVTEST_END</span>


    <span class="cp">`SVTEST</span><span class="p">(</span><span class="n">drive_write_addr_channel</span><span class="p">)</span>
      <span class="n">sequence_item</span> <span class="n">item</span> <span class="o">=</span> <span class="k">new</span><span class="p">(</span><span class="s">"item"</span><span class="p">);</span>
      <span class="cp">`FAIL_UNLESS</span><span class="p">(</span><span class="n">item</span><span class="p">.</span><span class="n">randomize</span><span class="p">()</span> <span class="k">with</span> <span class="o">{</span>
        <span class="n">id</span> <span class="o">==</span> <span class="mi">5</span><span class="p">;</span>
        <span class="n">address</span> <span class="o">==</span> <span class="mh">'h1122_3344</span><span class="p">;</span>
        <span class="n">length</span> <span class="o">==</span> <span class="n">LENGTH_14</span><span class="p">;</span>
        <span class="n">delay</span> <span class="o">==</span> <span class="mi">0</span><span class="p">;</span>
      <span class="o">}</span><span class="p">)</span>
      <span class="n">sequencer</span><span class="p">.</span><span class="n">add_item</span><span class="p">(</span><span class="n">item</span><span class="p">);</span>

      <span class="o">@</span><span class="p">(</span><span class="kt">posedge</span> <span class="n">clk</span><span class="p">);</span>
      <span class="cp">`FAIL_UNLESS</span><span class="p">(</span><span class="n">intf</span><span class="p">.</span><span class="n">AWID</span> <span class="o">==</span> <span class="mi">5</span><span class="p">)</span>
      <span class="cp">`FAIL_UNLESS</span><span class="p">(</span><span class="n">intf</span><span class="p">.</span><span class="n">AWADDR</span> <span class="o">==</span> <span class="mh">'h1122_3344</span><span class="p">)</span>
      <span class="cp">`FAIL_UNLESS</span><span class="p">(</span><span class="n">intf</span><span class="p">.</span><span class="n">AWLEN</span> <span class="o">==</span> <span class="mb">'b1101</span><span class="p">)</span>
    <span class="cp">`SVTEST_END</span>


    <span class="cp">`SVTEST</span><span class="p">(</span><span class="n">drive_wvalid__with_delay</span><span class="p">)</span>
      <span class="n">sequence_item</span> <span class="n">item</span> <span class="o">=</span> <span class="k">new</span><span class="p">(</span><span class="s">"item"</span><span class="p">);</span>
      <span class="cp">`FAIL_UNLESS</span><span class="p">(</span><span class="n">item</span><span class="p">.</span><span class="n">randomize</span><span class="p">()</span> <span class="k">with</span> <span class="o">{</span>
        <span class="n">delay</span> <span class="o">==</span> <span class="mi">0</span><span class="p">;</span>
        <span class="n">length</span> <span class="o">==</span> <span class="n">LENGTH_4</span><span class="p">;</span>
        <span class="n">transfers</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">delay</span> <span class="o">==</span> <span class="mi">1</span><span class="p">;</span>
        <span class="n">transfers</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">delay</span> <span class="o">==</span> <span class="mi">3</span><span class="p">;</span>
        <span class="n">transfers</span><span class="p">[</span><span class="mi">2</span><span class="p">].</span><span class="n">delay</span> <span class="o">==</span> <span class="mi">2</span><span class="p">;</span>
        <span class="n">transfers</span><span class="p">[</span><span class="mi">3</span><span class="p">].</span><span class="n">delay</span> <span class="o">==</span> <span class="mi">0</span><span class="p">;</span>
      <span class="o">}</span><span class="p">)</span>
      <span class="n">sequencer</span><span class="p">.</span><span class="n">add_item</span><span class="p">(</span><span class="n">item</span><span class="p">);</span>

      <span class="c1">// Skip over address phase</span>
      <span class="o">@</span><span class="p">(</span><span class="kt">posedge</span> <span class="n">clk</span><span class="p">);</span>

      <span class="o">@</span><span class="p">(</span><span class="kt">posedge</span> <span class="n">clk</span><span class="p">)</span> <span class="cp">`FAIL_UNLESS</span><span class="p">(</span><span class="n">intf</span><span class="p">.</span><span class="n">WVALID</span> <span class="o">===</span> <span class="mi">0</span><span class="p">)</span>
      <span class="o">@</span><span class="p">(</span><span class="kt">posedge</span> <span class="n">clk</span><span class="p">)</span> <span class="cp">`FAIL_UNLESS</span><span class="p">(</span><span class="n">intf</span><span class="p">.</span><span class="n">WVALID</span> <span class="o">===</span> <span class="mi">1</span><span class="p">)</span>

      <span class="kt">repeat</span> <span class="p">(</span><span class="mi">3</span><span class="p">)</span>
        <span class="o">@</span><span class="p">(</span><span class="kt">posedge</span> <span class="n">clk</span><span class="p">)</span> <span class="cp">`FAIL_UNLESS</span><span class="p">(</span><span class="n">intf</span><span class="p">.</span><span class="n">WVALID</span> <span class="o">===</span> <span class="mi">0</span><span class="p">)</span>
      <span class="o">@</span><span class="p">(</span><span class="kt">posedge</span> <span class="n">clk</span><span class="p">)</span> <span class="cp">`FAIL_UNLESS</span><span class="p">(</span><span class="n">intf</span><span class="p">.</span><span class="n">WVALID</span> <span class="o">===</span> <span class="mi">1</span><span class="p">)</span>

      <span class="kt">repeat</span> <span class="p">(</span><span class="mi">2</span><span class="p">)</span>
        <span class="o">@</span><span class="p">(</span><span class="kt">posedge</span> <span class="n">clk</span><span class="p">)</span> <span class="cp">`FAIL_UNLESS</span><span class="p">(</span><span class="n">intf</span><span class="p">.</span><span class="n">WVALID</span> <span class="o">===</span> <span class="mi">0</span><span class="p">)</span>
      <span class="o">@</span><span class="p">(</span><span class="kt">posedge</span> <span class="n">clk</span><span class="p">)</span> <span class="cp">`FAIL_UNLESS</span><span class="p">(</span><span class="n">intf</span><span class="p">.</span><span class="n">WVALID</span> <span class="o">===</span> <span class="mi">1</span><span class="p">)</span>

      <span class="o">@</span><span class="p">(</span><span class="kt">posedge</span> <span class="n">clk</span><span class="p">)</span> <span class="cp">`FAIL_UNLESS</span><span class="p">(</span><span class="n">intf</span><span class="p">.</span><span class="n">WVALID</span> <span class="o">===</span> <span class="mi">1</span><span class="p">)</span>
    <span class="cp">`SVTEST_END</span>


    <span class="cp">`SVTEST</span><span class="p">(</span><span class="n">drive_write_data_channel</span><span class="p">)</span>
      <span class="n">sequence_item</span> <span class="n">item</span> <span class="o">=</span> <span class="k">new</span><span class="p">(</span><span class="s">"item"</span><span class="p">);</span>
      <span class="cp">`FAIL_UNLESS</span><span class="p">(</span><span class="n">item</span><span class="p">.</span><span class="n">randomize</span><span class="p">()</span> <span class="k">with</span> <span class="o">{</span>
        <span class="n">delay</span> <span class="o">==</span> <span class="mi">0</span><span class="p">;</span>
        <span class="n">length</span> <span class="o">==</span> <span class="n">LENGTH_4</span><span class="p">;</span>
        <span class="n">transfers</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">data</span> <span class="o">==</span> <span class="mh">'hffff_ffff</span><span class="p">;</span>
        <span class="n">transfers</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">data</span> <span class="o">==</span> <span class="mh">'h0000_0000</span><span class="p">;</span>
        <span class="n">transfers</span><span class="p">[</span><span class="mi">2</span><span class="p">].</span><span class="n">data</span> <span class="o">==</span> <span class="mh">'haaaa_aaaa</span><span class="p">;</span>
        <span class="n">transfers</span><span class="p">[</span><span class="mi">3</span><span class="p">].</span><span class="n">data</span> <span class="o">==</span> <span class="mh">'h5555_5555</span><span class="p">;</span>
        <span class="n">transfers</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">delay</span> <span class="o">==</span> <span class="mi">0</span><span class="p">;</span>
        <span class="n">transfers</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">delay</span> <span class="o">==</span> <span class="mi">0</span><span class="p">;</span>
        <span class="n">transfers</span><span class="p">[</span><span class="mi">2</span><span class="p">].</span><span class="n">delay</span> <span class="o">==</span> <span class="mi">0</span><span class="p">;</span>
        <span class="n">transfers</span><span class="p">[</span><span class="mi">3</span><span class="p">].</span><span class="n">delay</span> <span class="o">==</span> <span class="mi">0</span><span class="p">;</span>
      <span class="o">}</span><span class="p">)</span>
      <span class="n">sequencer</span><span class="p">.</span><span class="n">add_item</span><span class="p">(</span><span class="n">item</span><span class="p">);</span>

      <span class="c1">// Skip over address phase</span>
      <span class="o">@</span><span class="p">(</span><span class="kt">posedge</span> <span class="n">clk</span><span class="p">);</span>

      <span class="o">@</span><span class="p">(</span><span class="kt">posedge</span> <span class="n">clk</span><span class="p">)</span> <span class="cp">`FAIL_UNLESS</span><span class="p">(</span><span class="n">intf</span><span class="p">.</span><span class="n">WDATA</span> <span class="o">===</span> <span class="mh">'hffff_ffff</span><span class="p">)</span>
      <span class="o">@</span><span class="p">(</span><span class="kt">posedge</span> <span class="n">clk</span><span class="p">)</span> <span class="cp">`FAIL_UNLESS</span><span class="p">(</span><span class="n">intf</span><span class="p">.</span><span class="n">WDATA</span> <span class="o">===</span> <span class="mh">'h0000_0000</span><span class="p">)</span>
      <span class="o">@</span><span class="p">(</span><span class="kt">posedge</span> <span class="n">clk</span><span class="p">)</span> <span class="cp">`FAIL_UNLESS</span><span class="p">(</span><span class="n">intf</span><span class="p">.</span><span class="n">WDATA</span> <span class="o">===</span> <span class="mh">'haaaa_aaaa</span><span class="p">)</span>
      <span class="o">@</span><span class="p">(</span><span class="kt">posedge</span> <span class="n">clk</span><span class="p">)</span> <span class="cp">`FAIL_UNLESS</span><span class="p">(</span><span class="n">intf</span><span class="p">.</span><span class="n">WDATA</span> <span class="o">===</span> <span class="mh">'h5555_5555</span><span class="p">)</span>
    <span class="cp">`SVTEST_END</span>


    <span class="cp">`SVTEST</span><span class="p">(</span><span class="n">drive_write_data_channel__data_held_until_wready</span><span class="p">)</span>
      <span class="n">sequence_item</span> <span class="n">item</span> <span class="o">=</span> <span class="k">new</span><span class="p">(</span><span class="s">"item"</span><span class="p">);</span>
      <span class="cp">`FAIL_UNLESS</span><span class="p">(</span><span class="n">item</span><span class="p">.</span><span class="n">randomize</span><span class="p">()</span> <span class="k">with</span> <span class="o">{</span>
        <span class="n">delay</span> <span class="o">==</span> <span class="mi">0</span><span class="p">;</span>
        <span class="n">length</span> <span class="o">==</span> <span class="n">LENGTH_4</span><span class="p">;</span>
        <span class="n">transfers</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">data</span> <span class="o">==</span> <span class="mh">'hffff_ffff</span><span class="p">;</span>
        <span class="n">transfers</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">data</span> <span class="o">==</span> <span class="mh">'h0000_0000</span><span class="p">;</span>
        <span class="n">transfers</span><span class="p">[</span><span class="mi">2</span><span class="p">].</span><span class="n">data</span> <span class="o">==</span> <span class="mh">'haaaa_aaaa</span><span class="p">;</span>
        <span class="n">transfers</span><span class="p">[</span><span class="mi">3</span><span class="p">].</span><span class="n">data</span> <span class="o">==</span> <span class="mh">'h5555_5555</span><span class="p">;</span>
        <span class="n">transfers</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">delay</span> <span class="o">==</span> <span class="mi">0</span><span class="p">;</span>
        <span class="n">transfers</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">delay</span> <span class="o">==</span> <span class="mi">0</span><span class="p">;</span>
        <span class="n">transfers</span><span class="p">[</span><span class="mi">2</span><span class="p">].</span><span class="n">delay</span> <span class="o">==</span> <span class="mi">0</span><span class="p">;</span>
        <span class="n">transfers</span><span class="p">[</span><span class="mi">3</span><span class="p">].</span><span class="n">delay</span> <span class="o">==</span> <span class="mi">0</span><span class="p">;</span>
      <span class="o">}</span><span class="p">)</span>
      <span class="n">sequencer</span><span class="p">.</span><span class="n">add_item</span><span class="p">(</span><span class="n">item</span><span class="p">);</span>

      <span class="c1">// Skip over address phase</span>
      <span class="o">@</span><span class="p">(</span><span class="kt">posedge</span> <span class="n">clk</span><span class="p">);</span>

      <span class="n">intf</span><span class="p">.</span><span class="n">WREADY</span> <span class="o">&lt;=</span> <span class="mi">0</span><span class="p">;</span>
      <span class="kt">repeat</span> <span class="p">(</span><span class="mi">3</span><span class="p">)</span>
        <span class="o">@</span><span class="p">(</span><span class="kt">posedge</span> <span class="n">clk</span><span class="p">)</span> <span class="cp">`FAIL_UNLESS</span><span class="p">(</span><span class="n">intf</span><span class="p">.</span><span class="n">WDATA</span> <span class="o">===</span> <span class="mh">'hffff_ffff</span><span class="p">)</span>
      <span class="n">intf</span><span class="p">.</span><span class="n">WREADY</span> <span class="o">&lt;=</span> <span class="mi">1</span><span class="p">;</span>
      <span class="o">@</span><span class="p">(</span><span class="kt">posedge</span> <span class="n">clk</span><span class="p">)</span> <span class="cp">`FAIL_UNLESS</span><span class="p">(</span><span class="n">intf</span><span class="p">.</span><span class="n">WDATA</span> <span class="o">===</span> <span class="mh">'hffff_ffff</span><span class="p">)</span>

      <span class="n">intf</span><span class="p">.</span><span class="n">WREADY</span> <span class="o">&lt;=</span> <span class="mi">0</span><span class="p">;</span>
      <span class="o">@</span><span class="p">(</span><span class="kt">posedge</span> <span class="n">clk</span><span class="p">)</span> <span class="cp">`FAIL_UNLESS</span><span class="p">(</span><span class="n">intf</span><span class="p">.</span><span class="n">WDATA</span> <span class="o">===</span> <span class="mh">'h0000_0000</span><span class="p">)</span>
      <span class="n">intf</span><span class="p">.</span><span class="n">WREADY</span> <span class="o">&lt;=</span> <span class="mi">1</span><span class="p">;</span>
      <span class="o">@</span><span class="p">(</span><span class="kt">posedge</span> <span class="n">clk</span><span class="p">)</span> <span class="cp">`FAIL_UNLESS</span><span class="p">(</span><span class="n">intf</span><span class="p">.</span><span class="n">WDATA</span> <span class="o">===</span> <span class="mh">'h0000_0000</span><span class="p">)</span>

      <span class="n">intf</span><span class="p">.</span><span class="n">WREADY</span> <span class="o">&lt;=</span> <span class="mi">0</span><span class="p">;</span>
      <span class="kt">repeat</span> <span class="p">(</span><span class="mi">2</span><span class="p">)</span>
        <span class="o">@</span><span class="p">(</span><span class="kt">posedge</span> <span class="n">clk</span><span class="p">)</span> <span class="cp">`FAIL_UNLESS</span><span class="p">(</span><span class="n">intf</span><span class="p">.</span><span class="n">WDATA</span> <span class="o">===</span> <span class="mh">'haaaa_aaaa</span><span class="p">)</span>
      <span class="n">intf</span><span class="p">.</span><span class="n">WREADY</span> <span class="o">&lt;=</span> <span class="mi">1</span><span class="p">;</span>
      <span class="o">@</span><span class="p">(</span><span class="kt">posedge</span> <span class="n">clk</span><span class="p">)</span> <span class="cp">`FAIL_UNLESS</span><span class="p">(</span><span class="n">intf</span><span class="p">.</span><span class="n">WDATA</span> <span class="o">===</span> <span class="mh">'haaaa_aaaa</span><span class="p">)</span>

      <span class="n">intf</span><span class="p">.</span><span class="n">WREADY</span> <span class="o">&lt;=</span> <span class="mi">0</span><span class="p">;</span>
      <span class="kt">repeat</span> <span class="p">(</span><span class="mi">4</span><span class="p">)</span>
        <span class="o">@</span><span class="p">(</span><span class="kt">posedge</span> <span class="n">clk</span><span class="p">)</span> <span class="cp">`FAIL_UNLESS</span><span class="p">(</span><span class="n">intf</span><span class="p">.</span><span class="n">WDATA</span> <span class="o">===</span> <span class="mh">'h5555_5555</span><span class="p">)</span>
      <span class="n">intf</span><span class="p">.</span><span class="n">WREADY</span> <span class="o">&lt;=</span> <span class="mi">1</span><span class="p">;</span>
      <span class="o">@</span><span class="p">(</span><span class="kt">posedge</span> <span class="n">clk</span><span class="p">)</span> <span class="cp">`FAIL_UNLESS</span><span class="p">(</span><span class="n">intf</span><span class="p">.</span><span class="n">WDATA</span> <span class="o">===</span> <span class="mh">'h5555_5555</span><span class="p">)</span>
    <span class="cp">`SVTEST_END</span>


    <span class="cp">`SVTEST</span><span class="p">(</span><span class="n">drive_write_data_channel__wlast_driven_for_last_transfer</span><span class="p">)</span>
      <span class="n">sequence_item</span> <span class="n">item</span> <span class="o">=</span> <span class="k">new</span><span class="p">(</span><span class="s">"item"</span><span class="p">);</span>
      <span class="cp">`FAIL_UNLESS</span><span class="p">(</span><span class="n">item</span><span class="p">.</span><span class="n">randomize</span><span class="p">()</span> <span class="k">with</span> <span class="o">{</span>
        <span class="n">delay</span> <span class="o">==</span> <span class="mi">0</span><span class="p">;</span>
        <span class="n">length</span> <span class="o">==</span> <span class="n">LENGTH_8</span><span class="p">;</span>
        <span class="k">foreach</span> <span class="p">(</span><span class="n">transfers</span><span class="p">[</span><span class="n">i</span><span class="p">])</span>
          <span class="n">transfers</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">delay</span> <span class="o">==</span> <span class="mi">0</span><span class="p">;</span>
      <span class="o">}</span><span class="p">)</span>
      <span class="n">sequencer</span><span class="p">.</span><span class="n">add_item</span><span class="p">(</span><span class="n">item</span><span class="p">);</span>

      <span class="c1">// Skip over address phase</span>
      <span class="o">@</span><span class="p">(</span><span class="kt">posedge</span> <span class="n">clk</span><span class="p">);</span>

      <span class="kt">repeat</span> <span class="p">(</span><span class="mi">7</span><span class="p">)</span>
        <span class="o">@</span><span class="p">(</span><span class="kt">posedge</span> <span class="n">clk</span><span class="p">)</span> <span class="cp">`FAIL_IF</span><span class="p">(</span><span class="n">intf</span><span class="p">.</span><span class="n">WLAST</span><span class="p">)</span>
      <span class="o">@</span><span class="p">(</span><span class="kt">posedge</span> <span class="n">clk</span><span class="p">)</span> <span class="cp">`FAIL_UNLESS</span><span class="p">(</span><span class="n">intf</span><span class="p">.</span><span class="n">WLAST</span><span class="p">)</span>
    <span class="cp">`SVTEST_END</span>
</code></pre></div></div>

<p>The tests above cover the desired functionality that we want to implement in our driver. We won’t go through each and every one of them and see what production code we need to write, since the actual implementation of the driver isn’t really important for this post. We want to focus more on the tests themselves.</p>

<p>When first confronted with these tests, a new developer won’t have an easy time understanding what’s going on. The tests are pretty verbose and it’s not immediately clear what the focus of each one is. Let’s see how we could improve this.</p>

<p>First, we’ll notice that the one thing we do in each test is to create an item and queue it for the driver. We use randomization to make sure that the item is “consistent”, meaning that the constraints defined in it hold. We could set item variables procedurally, but we would need to ensure that the length and the number of transfers match, which would mean even more code. Instead of repeating these steps in each unit test, we could centralize them into one place. Since we use randomization, we can’t extract a function. We’re forced to use a macro:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="cp">`define</span> <span class="n">add_item_with</span><span class="p">(</span><span class="n">CONSTRAINTS</span><span class="p">)</span> \
    <span class="n">sequence_item</span> <span class="n">item</span> <span class="o">=</span> <span class="k">new</span><span class="p">(</span><span class="s">"item"</span><span class="p">);</span> \
    <span class="cp">`FAIL_UNLESS</span><span class="p">(</span><span class="n">item</span><span class="p">.</span><span class="n">randomize</span><span class="p">()</span> <span class="k">with</span> <span class="n">CONSTRAINTS</span><span class="p">)</span> \
    <span class="n">sequencer</span><span class="p">.</span><span class="n">add_item</span><span class="p">(</span><span class="n">item</span><span class="p">);</span>
</code></pre></div></div>

<p>This is going to save us some lines of code and it’s going to make the intent of the code more obvious. What will differ between unit tests are the constraints they use when adding an item:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code>    <span class="cp">`SVTEST</span><span class="p">(</span><span class="n">drive_awvalid__with_delay</span><span class="p">)</span>
      <span class="cp">`add_item_with</span><span class="p">(</span><span class="o">{</span>
        <span class="n">delay</span> <span class="o">==</span> <span class="mi">3</span><span class="p">;</span>
      <span class="o">}</span><span class="p">)</span>

      <span class="c1">// ...</span>
    <span class="cp">`SVTEST_END</span>


    <span class="cp">`SVTEST</span><span class="p">(</span><span class="n">drive_awvalid__held_until_hready</span><span class="p">)</span>
      <span class="cp">`add_item_with</span><span class="p">(</span><span class="o">{</span>
        <span class="n">delay</span> <span class="o">==</span> <span class="mi">0</span><span class="p">;</span>
      <span class="o">}</span><span class="p">)</span>

      <span class="c1">// ...</span>
    <span class="cp">`SVTEST_END</span>


    <span class="cp">`SVTEST</span><span class="p">(</span><span class="n">drive_write_addr_channel</span><span class="p">)</span>
      <span class="cp">`add_item_with</span><span class="p">(</span><span class="o">{</span>
        <span class="n">id</span> <span class="o">==</span> <span class="mi">5</span><span class="p">;</span>
        <span class="n">address</span> <span class="o">==</span> <span class="mh">'h1122_3344</span><span class="p">;</span>
        <span class="n">length</span> <span class="o">==</span> <span class="n">LENGTH_14</span><span class="p">;</span>
        <span class="n">delay</span> <span class="o">==</span> <span class="mi">0</span><span class="p">;</span>
      <span class="o">}</span><span class="p">)</span>

      <span class="c1">// ...</span>
    <span class="cp">`SVTEST_END</span>
</code></pre></div></div>

<p>We can even go one step further. If we look at the tests again, we’ll notice that we use the same constraint over and over again to get an item without any delay. Also, whenever we want to check some write data channel aspects, we want to constrain the delay of each transfer to be zero. We do have tests where we want non-zero delays, but they are the exceptional cases. What we could do is to add some default values to the delay variables via soft constraints. This way, whenever we use the <code class="language-plaintext highlighter-rouge">`add_item_with(...)</code> macro we know that we’ll get an item without any delay:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="cp">`define</span> <span class="n">add_item_with</span><span class="p">(</span><span class="n">CONSTRAINTS</span><span class="p">)</span> \
    <span class="n">sequence_item</span> <span class="n">item</span> <span class="o">=</span> <span class="k">new</span><span class="p">(</span><span class="s">"item"</span><span class="p">);</span> \
    <span class="cp">`FAIL_UNLESS</span><span class="p">(</span><span class="n">item</span><span class="p">.</span><span class="n">randomize</span><span class="p">()</span> <span class="k">with</span> <span class="o">{</span> \
      <span class="n">soft</span> <span class="n">delay</span> <span class="o">==</span> <span class="mi">0</span><span class="p">;</span> \
      <span class="k">foreach</span> <span class="p">(</span><span class="n">transfers</span><span class="p">[</span><span class="n">i</span><span class="p">])</span> \
        <span class="n">soft</span> <span class="n">transfers</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">delay</span> <span class="o">==</span> <span class="mi">0</span><span class="p">;</span> \
      \
      <span class="k">if</span> <span class="p">(</span><span class="mi">1</span><span class="p">)</span> \
        <span class="n">CONSTRAINTS</span> \
    <span class="o">}</span><span class="p">)</span> \
    <span class="n">sequencer</span><span class="p">.</span><span class="n">add_item</span><span class="p">(</span><span class="n">item</span><span class="p">);</span>
</code></pre></div></div>

<p>This way, we can write even more compact code to add items. Here are the two data tests I mentioned:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code>    <span class="cp">`SVTEST</span><span class="p">(</span><span class="n">drive_write_data_channel</span><span class="p">)</span>
      <span class="cp">`add_item_with</span><span class="p">(</span><span class="o">{</span>
        <span class="n">length</span> <span class="o">==</span> <span class="n">LENGTH_4</span><span class="p">;</span>
        <span class="n">transfers</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">data</span> <span class="o">==</span> <span class="mh">'hffff_ffff</span><span class="p">;</span>
        <span class="n">transfers</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">data</span> <span class="o">==</span> <span class="mh">'h0000_0000</span><span class="p">;</span>
        <span class="n">transfers</span><span class="p">[</span><span class="mi">2</span><span class="p">].</span><span class="n">data</span> <span class="o">==</span> <span class="mh">'haaaa_aaaa</span><span class="p">;</span>
        <span class="n">transfers</span><span class="p">[</span><span class="mi">3</span><span class="p">].</span><span class="n">data</span> <span class="o">==</span> <span class="mh">'h5555_5555</span><span class="p">;</span>
      <span class="o">}</span><span class="p">)</span>

      <span class="c1">// ...</span>
    <span class="cp">`SVTEST_END</span>


    <span class="cp">`SVTEST</span><span class="p">(</span><span class="n">drive_write_data_channel__data_held_until_wready</span><span class="p">)</span>
      <span class="cp">`add_item_with</span><span class="p">(</span><span class="o">{</span>
        <span class="n">length</span> <span class="o">==</span> <span class="n">LENGTH_4</span><span class="p">;</span>
        <span class="n">transfers</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">data</span> <span class="o">==</span> <span class="mh">'hffff_ffff</span><span class="p">;</span>
        <span class="n">transfers</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">data</span> <span class="o">==</span> <span class="mh">'h0000_0000</span><span class="p">;</span>
        <span class="n">transfers</span><span class="p">[</span><span class="mi">2</span><span class="p">].</span><span class="n">data</span> <span class="o">==</span> <span class="mh">'haaaa_aaaa</span><span class="p">;</span>
        <span class="n">transfers</span><span class="p">[</span><span class="mi">3</span><span class="p">].</span><span class="n">data</span> <span class="o">==</span> <span class="mh">'h5555_5555</span><span class="p">;</span>
      <span class="o">}</span><span class="p">)</span>

      <span class="c1">// ...</span>
    <span class="cp">`SVTEST_END</span>
</code></pre></div></div>

<p>If we compare them with the initial version from the beginning of the post, we’ll see that they are much more compact. It’s also clearer that the handling of the <em>data</em> variables are what we’re testing and not anything related to delays.</p>

<p>Since we want to check the behavior of signals at certain points in time, we need to do a lot of waits. The statement <code class="language-plaintext highlighter-rouge">@(posedge clk)</code> comes up a lot in our unit tests. We could shorten this by using a default <strong>clocking</strong> block:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">module</span> <span class="n">master_driver_unit_test</span><span class="p">;</span>
  <span class="c1">// ...</span>

  <span class="k">default</span> <span class="k">clocking</span> <span class="o">@</span><span class="p">(</span><span class="kt">posedge</span> <span class="n">clk</span><span class="p">);</span>
  <span class="k">endclocking</span>
<span class="k">endmodule</span>
</code></pre></div></div>

<p>Now, instead of using the verbose <code class="language-plaintext highlighter-rouge">@(posedge clk)</code> statement, we can use the cycle delay operator:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code>    <span class="cp">`SVTEST</span><span class="p">(</span><span class="n">drive_wvalid__with_delay</span><span class="p">)</span>
      <span class="c1">// ...</span>

      <span class="c1">// Skip over address phase</span>
      <span class="p">##</span><span class="mi">1</span><span class="p">;</span>

      <span class="p">##</span><span class="mi">1</span> <span class="cp">`FAIL_UNLESS</span><span class="p">(</span><span class="n">intf</span><span class="p">.</span><span class="n">WVALID</span> <span class="o">===</span> <span class="mi">0</span><span class="p">)</span>
      <span class="p">##</span><span class="mi">1</span> <span class="cp">`FAIL_UNLESS</span><span class="p">(</span><span class="n">intf</span><span class="p">.</span><span class="n">WVALID</span> <span class="o">===</span> <span class="mi">1</span><span class="p">)</span>

      <span class="kt">repeat</span> <span class="p">(</span><span class="mi">3</span><span class="p">)</span>
        <span class="p">##</span><span class="mi">1</span> <span class="cp">`FAIL_UNLESS</span><span class="p">(</span><span class="n">intf</span><span class="p">.</span><span class="n">WVALID</span> <span class="o">===</span> <span class="mi">0</span><span class="p">)</span>
      <span class="p">##</span><span class="mi">1</span> <span class="cp">`FAIL_UNLESS</span><span class="p">(</span><span class="n">intf</span><span class="p">.</span><span class="n">WVALID</span> <span class="o">===</span> <span class="mi">1</span><span class="p">)</span>

      <span class="kt">repeat</span> <span class="p">(</span><span class="mi">2</span><span class="p">)</span>
        <span class="p">##</span><span class="mi">1</span> <span class="cp">`FAIL_UNLESS</span><span class="p">(</span><span class="n">intf</span><span class="p">.</span><span class="n">WVALID</span> <span class="o">===</span> <span class="mi">0</span><span class="p">)</span>
      <span class="p">##</span><span class="mi">1</span> <span class="cp">`FAIL_UNLESS</span><span class="p">(</span><span class="n">intf</span><span class="p">.</span><span class="n">WVALID</span> <span class="o">===</span> <span class="mi">1</span><span class="p">)</span>

      <span class="p">##</span><span class="mi">1</span> <span class="cp">`FAIL_UNLESS</span><span class="p">(</span><span class="n">intf</span><span class="p">.</span><span class="n">WVALID</span> <span class="o">===</span> <span class="mi">1</span><span class="p">)</span>
    <span class="cp">`SVTEST_END</span>
</code></pre></div></div>

<p>Having less words to parse makes the test’s intent clearer. Using a default clocking block is an option most of the time, but if you have a more exotic protocol that uses both edges of the clock or multiple clocks altogether, it’s not going to work.</p>

<p>One thing you may have noticed is that I’ve marked some wait statements with comments. If you’ve read <a href="https://www.amazon.com/gp/product/0132350882/ref=as_li_tl?ie=UTF8&amp;camp=1789&amp;creative=9325&amp;creativeASIN=0132350882&amp;linkCode=as2&amp;tag=verificgentle-20&amp;linkId=7a24303f0bef4456c46f90820f462e30">Clean Code</a> (and if you haven’t you should), you’ll call me out on this. Uncle Bob says that comments are a crutch for poorly written code that doesn’t express its intent properly. Instead of relying on comments, we could create a named task:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="k">task</span> <span class="n">wait_addr_phase_ended</span><span class="p">();</span>
    <span class="p">##</span><span class="mi">1</span><span class="p">;</span>
  <span class="k">endtask</span>
</code></pre></div></div>

<p>Now, when a test calls this task, it’ll be immediately apparent what the intention is:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code>    <span class="cp">`SVTEST</span><span class="p">(</span><span class="n">drive_write_data_channel</span><span class="p">)</span>
      <span class="cp">`add_item_with</span><span class="p">(</span><span class="o">{</span>
        <span class="c1">// ...</span>
      <span class="o">}</span><span class="p">)</span>

      <span class="n">wait_addr_phase_ended</span><span class="p">();</span>

      <span class="c1">// ...</span>
    <span class="cp">`SVTEST_END</span>
</code></pre></div></div>

<p>There is a mismatch between what the task does and its name. The task actually just waits for one cycle. To reflect this, it should have been named <code class="language-plaintext highlighter-rouge">wait_cycle()</code>. A task call like this will take us back to square one in terms of test readability. We may as well just use the <code class="language-plaintext highlighter-rouge">##1</code> statement as that tells us the same thing. If we want to solve this mismatch between the task name and its implementation, we should change the latter. In the context of our tests, we knew that the address phase was going to end after one clock cycle. Generally, though, What we want is to wait for <em>AWVALID</em> and <em>AWREADY</em> to be high at the same time:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="k">task</span> <span class="n">wait_addr_phase_ended</span><span class="p">();</span>
    <span class="o">@</span><span class="p">(</span><span class="kt">posedge</span> <span class="n">clk</span> <span class="k">iff</span> <span class="n">intf</span><span class="p">.</span><span class="n">AWVALID</span> <span class="o">&amp;&amp;</span> <span class="n">intf</span><span class="p">.</span><span class="n">AWREADY</span><span class="p">);</span>
  <span class="k">endtask</span>
</code></pre></div></div>

<p>Some unit-testing purists might bash this method because it adds complexity to the testing logic. This is something we should try to avoid, since we don’t want to have to start testing our tests. The task is lean enough that I’d say this point doesn’t apply here.</p>

<p>While we may have streamlined our test preparation code, checking that our expectations are fulfilled is ridiculously long. Procedural code isn’t really well suited to check behavior over time. You know what is though? Assertions… Instead of writing a big mess of procedural code that does <strong>repeats</strong> and cycle delays, we could write a nice <strong>property</strong> and check that it holds. When people hear the word <strong>property</strong>, they normally think of concurrent assertions, but this isn’t really what we want here. What we want to do is to check that a certain <strong>property</strong> holds after a certain point in time, not during the whole simulation.</p>

<p>Luckily, <em>SystemVerilog</em> provides the <strong>expect</strong> construct, which does exactly what we want. Given a <strong>property</strong>, it will begin evaluating it starting with the first subsequent clock. For example, to check that the driver can drive data transfers with delays, we could write the following:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code>    <span class="cp">`SVTEST</span><span class="p">(</span><span class="n">drive_wvalid__with_delay</span><span class="p">)</span>
      <span class="c1">// ...</span>

      <span class="k">expect</span> <span class="p">(</span>
        <span class="n">intf</span><span class="p">.</span><span class="n">WVALID</span> <span class="o">===</span> <span class="mi">0</span>
          <span class="p">##</span><span class="mi">1</span> <span class="n">intf</span><span class="p">.</span><span class="n">WVALID</span> <span class="o">===</span> <span class="mi">1</span>
          <span class="p">##</span><span class="mi">1</span> <span class="n">intf</span><span class="p">.</span><span class="n">WVALID</span> <span class="o">===</span> <span class="mi">0</span> <span class="p">[</span><span class="o">*</span><span class="mi">3</span><span class="p">]</span>
          <span class="p">##</span><span class="mi">1</span> <span class="n">intf</span><span class="p">.</span><span class="n">WVALID</span> <span class="o">===</span> <span class="mi">1</span>
          <span class="p">##</span><span class="mi">1</span> <span class="n">intf</span><span class="p">.</span><span class="n">WVALID</span> <span class="o">===</span> <span class="mi">0</span> <span class="p">[</span><span class="o">*</span><span class="mi">2</span><span class="p">]</span>
          <span class="p">##</span><span class="mi">1</span> <span class="n">intf</span><span class="p">.</span><span class="n">WVALID</span> <span class="o">===</span> <span class="mi">1</span>
          <span class="p">##</span><span class="mi">1</span> <span class="n">intf</span><span class="p">.</span><span class="n">WVALID</span> <span class="o">===</span> <span class="mi">1</span><span class="p">)</span>
      <span class="k">else</span>
        <span class="cp">`FAIL_IF</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
    <span class="cp">`SVTEST_END</span>
</code></pre></div></div>

<p>This is much cleaner than the procedural code we had before. It also allows us to structure our unit tests according to the Arrange, Act, Assert pattern (even though most of the time for drivers Arrange and Act get a bit mixed, but at least Assert is separated clearly).</p>

<p>Since expecting that properties hold is something we’ll want to do over and over again, let’s wrap it in a utility macro and make it part of the <a href="https://github.com/tudortimi/vgm_svunit_utils"><em>vgm_svunit_utils</em></a> package:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">`define</span> <span class="n">FAIL_UNLESS_PROP</span><span class="p">(</span><span class="n">prop</span><span class="p">)</span> \
  <span class="k">expect</span> <span class="p">(</span><span class="n">prop</span><span class="p">)</span> \
  <span class="k">else</span> \
    <span class="cp">`FAIL_IF</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
</code></pre></div></div>

<p>Using this macro will give the unit tests a more consistent <a href="https://github.com/nosnhojn/svunit-code">SVUnit</a> look and feel:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code>    <span class="cp">`SVTEST</span><span class="p">(</span><span class="n">drive_wvalid__with_delay</span><span class="p">)</span>
      <span class="c1">// ...</span>

      <span class="cp">`FAIL_UNLESS_PROP</span><span class="p">(</span>
        <span class="n">intf</span><span class="p">.</span><span class="n">WVALID</span> <span class="o">===</span> <span class="mi">0</span>
          <span class="p">##</span><span class="mi">1</span> <span class="n">intf</span><span class="p">.</span><span class="n">WVALID</span> <span class="o">===</span> <span class="mi">1</span>
          <span class="p">##</span><span class="mi">1</span> <span class="n">intf</span><span class="p">.</span><span class="n">WVALID</span> <span class="o">===</span> <span class="mi">0</span> <span class="p">[</span><span class="o">*</span><span class="mi">3</span><span class="p">]</span>
          <span class="c1">// ...</span>
      <span class="p">)</span>
    <span class="cp">`SVTEST_END</span>
</code></pre></div></div>

<p>As we saw in the previous post, it’s very important to use the <strong>===</strong> (4-state equality) operator instead of <strong>==</strong>, otherwise we’re writing tests that always pass. I intentionally wrote the <em>drive_write_addr_channel</em> buggy to show this (kudos to anyone who noticed). Also, we need to watch out for hidden comparisons. In the last test we didn’t even use the equality operator:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code>    <span class="cp">`SVTEST</span><span class="p">(</span><span class="n">drive_write_data_channel__wlast_driven_for_last_transfer</span><span class="p">)</span>
      <span class="c1">// ...</span>

      <span class="kt">repeat</span> <span class="p">(</span><span class="mi">7</span><span class="p">)</span>
        <span class="o">@</span><span class="p">(</span><span class="kt">posedge</span> <span class="n">clk</span><span class="p">)</span> <span class="cp">`FAIL_IF</span><span class="p">(</span><span class="n">intf</span><span class="p">.</span><span class="n">WLAST</span><span class="p">)</span>
      <span class="o">@</span><span class="p">(</span><span class="kt">posedge</span> <span class="n">clk</span><span class="p">)</span> <span class="cp">`FAIL_UNLESS</span><span class="p">(</span><span class="n">intf</span><span class="p">.</span><span class="n">WLAST</span><span class="p">)</span>
    <span class="cp">`SVTEST_END</span>
</code></pre></div></div>

<p>Because of the way the <code class="language-plaintext highlighter-rouge">`FAIL_*</code> macros are written, they will both always pass, so the test isn’t really doing anything. If we were to re-write them using properties, we would notice if <em>WLAST</em> isn’t being driven:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code>    <span class="cp">`SVTEST</span><span class="p">(</span><span class="n">drive_write_data_channel__wlast_driven_for_last_transfer</span><span class="p">)</span>
      <span class="c1">// ...</span>

      <span class="cp">`FAIL_UNLESS_PROP</span><span class="p">(</span>
        <span class="o">!</span><span class="n">intf</span><span class="p">.</span><span class="n">WLAST</span> <span class="p">[</span><span class="o">*</span><span class="mi">7</span><span class="p">]</span>
          <span class="p">##</span><span class="mi">1</span> <span class="n">intf</span><span class="p">.</span><span class="n">WLAST</span><span class="p">)</span>
    <span class="cp">`SVTEST_END</span>
</code></pre></div></div>

<p>If <em>WLAST</em> were to be <em>X</em>, then the negation would also return <em>X</em>, which would be interpreted as a <em>0</em>, leading to a fail of the property. For single bit signals, using properties is much safer than comparing for equality. There’s also the added bonus that the code is more compact. For vectors, though, we still need to make sure that we’re using the <strong>===</strong> operator.</p>

<p>Another cool thing that properties allow us to do is to focus more on the aspects that are important for a test. For example, in the <em>data_held_until_ready</em> test we want to check that the driver doesn’t modify the value of <em>WDATA</em> until it sees a corresponding <em>WREADY</em>. We did this by choosing known values for the data transfers and checking that these values stay on the bus for the appropriate number of clock cycles. Actually, we don’t (or shouldn’t) care what data is being driven, as long as it stays constant. We could simplify the code to the following:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code>    <span class="cp">`SVTEST</span><span class="p">(</span><span class="n">drive_write_data_channel__data_held_until_wready</span><span class="p">)</span>
      <span class="cp">`add_item_with</span><span class="p">(</span><span class="o">{</span>
        <span class="n">length</span> <span class="o">==</span> <span class="n">LENGTH_4</span><span class="p">;</span>
      <span class="o">}</span><span class="p">)</span>

      <span class="c1">// ...</span>

      <span class="cp">`FAIL_UNLESS_PROP</span><span class="p">(</span>
        <span class="n">stable_for</span><span class="p">(</span><span class="n">intf</span><span class="p">.</span><span class="n">WDATA</span><span class="p">,</span> <span class="mi">3</span><span class="p">)</span>
          <span class="p">##</span><span class="mi">1</span> <span class="n">stable_for</span><span class="p">(</span><span class="n">intf</span><span class="p">.</span><span class="n">WDATA</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
          <span class="p">##</span><span class="mi">1</span> <span class="n">stable_for</span><span class="p">(</span><span class="n">intf</span><span class="p">.</span><span class="n">WDATA</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span>
          <span class="p">##</span><span class="mi">1</span> <span class="n">stable_for</span><span class="p">(</span><span class="n">intf</span><span class="p">.</span><span class="n">WDATA</span><span class="p">,</span> <span class="mi">4</span><span class="p">))</span>
    <span class="cp">`SVTEST_END</span>
</code></pre></div></div>

<p>The <em>stable_for(…)</em> sequence only exists because my simulator complained about using <code class="language-plaintext highlighter-rouge">$past(...)</code> inside an <strong>expect</strong> statement. It’s content could have been inlined to the property:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="k">sequence</span> <span class="n">stable_for</span><span class="p">(</span><span class="n">signal</span><span class="p">,</span> <span class="kt">int</span> <span class="kt">unsigned</span> <span class="n">num_cycles</span><span class="p">);</span>
    <span class="p">##</span><span class="mi">1</span> <span class="p">($</span><span class="nb">stable</span><span class="p">(</span><span class="n">signal</span><span class="p">)</span> <span class="p">[</span><span class="o">*</span><span class="n">num_cycles</span><span class="p">]);</span>
  <span class="k">endsequence</span>
</code></pre></div></div>

<p>We don’t really need to use a property to check that the signal stays stable. As per the LRM we could use the <code class="language-plaintext highlighter-rouge">$stable(...)</code> system function inside procedural code as well, but some tools don’t allow this, limiting its use to assertions.</p>

<p>While it’s usually frowned upon to have randomness in unit tests, I would argue that this isn’t necessarily a problem here. Randomness should be avoided because it causes us to write complicated code for our expectations. As long as we don’t need to do this (i.e. the checking code stays the same regardless of what we plug into it), everything should be fine. There is one caveat, though. On the off chance that two consecutive transfers contain the same data, it won’t be possible to figure out whether the driver moved to the second transfer too early. In the extreme case, all transfers could have the same data value, making it impossible to check that the driver really holds transfers constant for their entire durations. This could be solved by writing a constraint that all data values should be unique.</p>

<p>Last, but not least, I hinted in the <a href="/2016/08/07/testing-uvm-drivers.html">previous post</a> that a driver not only drives items from the sequencer. It’s also supposed to request items from the sequencer at well defined points in time. For example, a driver should call <code class="language-plaintext highlighter-rouge">get_next_item(...)</code> once it’s able to process a new item, but not before, to allow the running sequence to randomize items at the latest possible time (so called <em>late randomization</em>). This is helpful when sequences use the current state of the system to decide what to do next. For simple protocols this is easy: a new item can start exactly after the previous one has finished. For pipelined protocols, though, it’s a not as easy. The AXI protocol is massively pipelined and can have a lot of ongoing transactions at any time. I don’t want to have to think what a sensible definition for an available slot for a new item would be, because the scheme would probably be too complicated. I do however want to show how we could verify that a driver calls sequencer methods at defined times.</p>

<p>We’ll take a contrived example of how to handle responses, since I couldn’t think of anything better. Whether we’re checking that <code class="language-plaintext highlighter-rouge">put_response(...)</code> or <code class="language-plaintext highlighter-rouge">get_next_item(...)</code> was called when expected doesn’t really matter, so this example should be enough to prove a point. Let’s say that when a response comes on the write response channel, the driver is supposed to let the sequencer know.</p>

<p>We’ll have another sequence item for the response:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">typedef</span> <span class="kt">enum</span> <span class="o">{</span> <span class="n">OKAY</span><span class="p">,</span> <span class="n">EXOKAY</span><span class="p">,</span> <span class="n">SLVERR</span><span class="p">,</span> <span class="n">DECERR</span> <span class="o">}</span> <span class="n">response_kind_e</span><span class="p">;</span>

<span class="kt">class</span> <span class="n">response</span> <span class="k">extends</span> <span class="n">uvm_sequence_item</span><span class="p">;</span>
  <span class="kt">bit</span> <span class="p">[</span><span class="mi">3</span><span class="o">:</span><span class="mi">0</span><span class="p">]</span> <span class="n">id</span><span class="p">;</span>
  <span class="n">response_kind_e</span> <span class="n">kind</span><span class="p">;</span>

  <span class="c1">// ...</span>
<span class="k">endclass</span>
</code></pre></div></div>

<p>First of all, we’ll want to check that the response contains the proper values:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code>    <span class="cp">`SVTEST</span><span class="p">(</span><span class="n">put_response_when_ready</span><span class="p">)</span>
      <span class="n">response</span> <span class="n">rsp</span><span class="p">;</span>

      <span class="n">intf</span><span class="p">.</span><span class="n">BID</span> <span class="o">&lt;=</span> <span class="mi">5</span><span class="p">;</span>
      <span class="n">intf</span><span class="p">.</span><span class="n">BVALID</span> <span class="o">&lt;=</span> <span class="mi">1</span><span class="p">;</span>
      <span class="p">##</span><span class="mi">1</span><span class="p">;</span>

      <span class="n">intf</span><span class="p">.</span><span class="n">BREADY</span> <span class="o">&lt;=</span> <span class="mi">1</span><span class="p">;</span>
      <span class="p">##</span><span class="mi">1</span><span class="p">;</span>

      <span class="n">uvm_wait_for_nba_region</span><span class="p">();</span>
      <span class="cp">`FAIL_UNLESS</span><span class="p">(</span><span class="n">sequencer</span><span class="p">.</span><span class="n">try_get_rsp</span><span class="p">(</span><span class="n">rsp</span><span class="p">))</span>
      <span class="cp">`FAIL_UNLESS</span><span class="p">(</span><span class="n">rsp</span><span class="p">.</span><span class="n">id</span> <span class="o">==</span> <span class="mi">5</span><span class="p">)</span>
    <span class="cp">`SVTEST_END</span>
</code></pre></div></div>

<p>The driver waits for a response to be seen on the bus and calls <code class="language-plaintext highlighter-rouge">put_response(...)</code> when this is the case:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">class</span> <span class="n">master_driver</span> <span class="k">extends</span> <span class="n">uvm_driver</span> <span class="p">#(</span><span class="n">sequence_item</span><span class="p">,</span> <span class="n">response</span><span class="p">);</span>
  <span class="c1">// ..</span>

  <span class="kt">virtual</span> <span class="k">protected</span> <span class="k">task</span> <span class="n">collect_and_put</span><span class="p">();</span>
    <span class="k">forever</span> <span class="k">begin</span>
      <span class="n">collect</span><span class="p">();</span>
      <span class="n">seq_item_port</span><span class="p">.</span><span class="n">put_response</span><span class="p">(</span><span class="n">rsp</span><span class="p">);</span>
    <span class="k">end</span>
  <span class="k">endtask</span>

  <span class="kt">virtual</span> <span class="k">protected</span> <span class="k">task</span> <span class="n">collect</span><span class="p">();</span>
    <span class="o">@</span><span class="p">(</span><span class="n">intf</span><span class="p">.</span><span class="n">ACLK</span> <span class="k">iff</span> <span class="n">intf</span><span class="p">.</span><span class="n">BVALID</span><span class="p">);</span>
    <span class="n">rsp</span> <span class="o">=</span> <span class="n">response</span><span class="o">::</span><span class="n">type_id</span><span class="o">::</span><span class="n">create</span><span class="p">(</span><span class="s">"rsp"</span><span class="p">);</span>
    <span class="n">rsp</span><span class="p">.</span><span class="n">id</span> <span class="o">=</span> <span class="n">intf</span><span class="p">.</span><span class="n">BID</span><span class="p">;</span>
  <span class="k">endtask</span>
<span class="k">endclass</span>
</code></pre></div></div>

<p>The test is going to pass with this implementation. The problem is, though, that the response is considered to be done only once it has also been accepted, i.e. <em>BREADY</em> goes high. Unfortunately, the previous code sends responses too early. We’ll need to update our unit test to check that <code class="language-plaintext highlighter-rouge">put_response(...)</code> was called after <em>BREADY</em> was also high and that it was called only once. This is where the test diagnostic information that <em>sequencer_stub</em> provides is going to be useful:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code>    <span class="cp">`SVTEST</span><span class="p">(</span><span class="n">put_response_when_ready</span><span class="p">)</span>
      <span class="c1">// ...</span>

      <span class="n">intf</span><span class="p">.</span><span class="n">BREADY</span> <span class="o">&lt;=</span> <span class="mi">1</span><span class="p">;</span>
      <span class="p">##</span><span class="mi">1</span><span class="p">;</span>

      <span class="cp">`FAIL_UNLESS_TRIGGERED</span><span class="p">(</span><span class="n">sequencer</span><span class="p">.</span><span class="n">put_response_called</span><span class="p">)</span>
      <span class="cp">`FAIL_UNLESS</span><span class="p">(</span><span class="n">sequencer</span><span class="p">.</span><span class="n">num_put_response_calls</span> <span class="o">==</span> <span class="mi">1</span><span class="p">)</span>

      <span class="c1">// ...</span>
    <span class="cp">`SVTEST_END</span>
</code></pre></div></div>

<p>The <em>sequencer_stub</em> class contains a named event <em>put_response_called</em> that, as the name suggests, is triggered when <code class="language-plaintext highlighter-rouge">put_reponse(...)</code> is called by the driver. The <code class="language-plaintext highlighter-rouge">`FAIL_UNLESS_TRIGGERED(...)</code> macro is part of the <a href="https://github.com/tudortimi/vgm_svunit_utils"><em>vgm_svunit_utils</em></a> package. It wraps the code required to check that an event was triggered in the current time step:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">`define</span> <span class="n">FAIL_UNLESS_TRIGGERED</span><span class="p">(</span><span class="n">ev</span><span class="p">)</span> \
  <span class="k">fork</span> \
    <span class="k">wait</span> <span class="p">(</span><span class="n">ev</span><span class="p">.</span><span class="n">triggered</span><span class="p">);</span> \
    \
    <span class="k">begin</span> \
      <span class="p">#</span><span class="mi">1</span><span class="p">;</span> \
      <span class="cp">`FAIL_IF_LOG</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="err">`</span><span class="s">"'ev' not triggered`"</span><span class="p">)</span> \
    <span class="k">end</span> \
  <span class="k">join_any</span> \
  <span class="kt">disable</span> <span class="k">fork</span><span class="p">;</span>
</code></pre></div></div>

<p>The <strong>wait</strong> statement checks if the event was already triggered (because the driver code could have executed first) and if it wasn’t, it blocks. If time moves forward and the event didn’t get triggered, an error message is triggered. Since the test will now fail, we’ll need to update the driver code (not shown).</p>

<p>We’ve covered a lot of ground in this post on how to write more comprehensive, readable and maintainable unit tests for UVM drivers. You can find the example code <a href="https://github.com/verification-gentleman-blog/testing_uvm_drivers_pt2">here</a>. I hope this helps you be more productive when developing your own drivers.</p>]]></content><author><name>Tudor Timi</name></author><category term="SVUnit" /><category term="SystemVerilog" /><category term="Unit testing" /><summary type="html"><![CDATA[In the previous post we looked at how we can emulate sequencer/driver communication using a lightweight stub of uvm_sequencer. Let’s also look at some more tips and tricks I’ve picked up while writing unit tests for drivers. To mix things up a bit, let’s look at the AXI protocol. We’re not going to implement a full featured driver; instead, we’ll focus on the write channels:]]></summary></entry><entry><title type="html">Testing UVM Drivers</title><link href="https://blog.verificationgentleman.com/2016/08/07/testing-uvm-drivers.html" rel="alternate" type="text/html" title="Testing UVM Drivers" /><published>2016-08-07T18:06:00+02:00</published><updated>2016-08-07T18:06:00+02:00</updated><id>https://blog.verificationgentleman.com/2016/08/07/testing-uvm-drivers</id><content type="html" xml:base="https://blog.verificationgentleman.com/2016/08/07/testing-uvm-drivers.html"><![CDATA[<p>It’s that time again when I’ve started a new project at work. Since we’re going to be using some new proprietary interfaces in this chip, this calls for some new UVCs. I wouldn’t even consider developing a new UVC without setting up a unit testing environment for it first. Since this is a greenfield project, a lot of the specifications are volatile, meaning that the interface protocol can change at any moment. Having tests in place can help make sure that I don’t miss anything. Even if the specification stays the same, I might decide to restructure the code and I want to be certain that it still works.</p>

<p>I first started with unit testing about two years ago, while developing some other interface UVCs. I’ve learned a few things throughout this time and I’d like to share some of the techniques I’ve used. In this post we’ll look at how to test UVM drivers.</p>

<p>A driver is supposed to take a transaction (called a sequence item in UVM lingo) and convert it into signal toggles. Testing a driver is conceptually pretty straightforward: we supply it with an item and we check that the toggles it produces are correct. As an example, we’ll take the <a href="http://cdn.opencores.org/downloads/wbspec_b3.pdf">Wishbone protocol, revision B.3</a>. Our sequence item models the properties of an access:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">typedef</span> <span class="kt">enum</span> <span class="o">{</span> <span class="n">READ</span><span class="p">,</span> <span class="n">WRITE</span> <span class="o">}</span> <span class="n">direction_e</span><span class="p">;</span>


<span class="kt">class</span> <span class="n">sequence_item</span> <span class="k">extends</span> <span class="n">uvm_sequence_item</span><span class="p">;</span>
  <span class="k">rand</span> <span class="n">direction_e</span> <span class="n">direction</span><span class="p">;</span>
  <span class="k">rand</span> <span class="kt">bit</span><span class="p">[</span><span class="mi">31</span><span class="o">:</span><span class="mi">0</span><span class="p">]</span> <span class="n">address</span><span class="p">;</span>
  <span class="k">rand</span> <span class="kt">bit</span><span class="p">[</span><span class="mi">31</span><span class="o">:</span><span class="mi">0</span><span class="p">]</span> <span class="n">data</span><span class="p">;</span>

  <span class="k">rand</span> <span class="kt">int</span> <span class="kt">unsigned</span> <span class="n">delay</span><span class="p">;</span>

  <span class="c1">// ...</span>
<span class="k">endclass</span>
</code></pre></div></div>

<p>Aside from the direction, address and data, we can also randomize how many clock cycles the driver should wait before starting the transfer.</p>

<p>All the drivers I’ve seen up to now consisted primarily of a loop in which an item is fetched and then driven:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">class</span> <span class="n">master_driver</span> <span class="k">extends</span> <span class="n">uvm_driver</span> <span class="p">#(</span><span class="n">sequence_item</span><span class="p">);</span>
  <span class="kt">virtual</span> <span class="k">task</span> <span class="n">run_phase</span><span class="p">(</span><span class="n">uvm_phase</span> <span class="n">phase</span><span class="p">);</span>
    <span class="k">forever</span> <span class="k">begin</span>
      <span class="n">seq_item_port</span><span class="p">.</span><span class="n">get_next_item</span><span class="p">(</span><span class="n">req</span><span class="p">);</span>
      <span class="n">drive</span><span class="p">();</span>
      <span class="n">seq_item_port</span><span class="p">.</span><span class="n">item_done</span><span class="p">();</span>
    <span class="k">end</span>
  <span class="k">endtask</span>

  <span class="c1">// ...</span>
<span class="k">endclass</span>
</code></pre></div></div>

<p>Our goal is to write the <em>drive()</em> task.</p>

<p>Let’s look at how to supply a driver with an item. A driver is an active component, that asks for items at its own pace. Inside an agent, it’s connected to a sequencer, that feeds it with items when they become available. Inside our unit test, we need to emulate the same relationship by having a test double which the driver can interrogate. There’s nothing stopping us from using <em>uvm_sequencer</em> itself:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">module</span> <span class="n">master_driver_unit_test</span><span class="p">;</span>
  <span class="n">master_driver</span> <span class="n">driver</span><span class="p">;</span>
  <span class="n">uvm_sequencer</span> <span class="p">#(</span><span class="n">sequence_item</span><span class="p">)</span> <span class="n">sequencer</span><span class="p">;</span>


  <span class="k">function</span> <span class="kt">void</span> <span class="n">build</span><span class="p">();</span>
    <span class="n">svunit_ut</span> <span class="o">=</span> <span class="k">new</span><span class="p">(</span><span class="n">name</span><span class="p">);</span>

    <span class="n">driver</span> <span class="o">=</span> <span class="k">new</span><span class="p">(</span><span class="s">"driver"</span><span class="p">,</span> <span class="k">null</span><span class="p">);</span>
    <span class="n">sequencer</span> <span class="o">=</span> <span class="k">new</span><span class="p">(</span><span class="s">"sequencer"</span><span class="p">,</span> <span class="k">null</span><span class="p">);</span>
    <span class="n">driver</span><span class="p">.</span><span class="n">seq_item_port</span><span class="p">.</span><span class="n">connect</span><span class="p">(</span><span class="n">sequencer</span><span class="p">.</span><span class="n">seq_item_export</span><span class="p">);</span>
  <span class="k">endfunction</span>

  <span class="c1">// ...</span>
<span class="k">endmodule</span>
</code></pre></div></div>

<p>The first test we want to write is that when the driver gets an item with no delay, it drives <em>CYC_O</em> and <em>STB_O</em> immediately. We first create an item and we start it on the sequencer using <em>execute_item(…)</em>. This models a <code class="language-plaintext highlighter-rouge">`uvm_send(...)</code> action inside a sequence:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">module</span> <span class="n">master_driver_unit_test</span><span class="p">;</span>

  <span class="cp">`SVTEST</span><span class="p">(</span><span class="n">cyc_and_stb_driven</span><span class="p">)</span>
    <span class="n">sequence_item</span> <span class="n">item</span> <span class="o">=</span> <span class="k">new</span><span class="p">(</span><span class="s">"item"</span><span class="p">);</span>

    <span class="k">fork</span>
      <span class="n">sequencer</span><span class="p">.</span><span class="n">execute_item</span><span class="p">(</span><span class="n">item</span><span class="p">);</span>
    <span class="k">join_none</span>

    <span class="o">@</span><span class="p">(</span><span class="kt">posedge</span> <span class="n">clk</span><span class="p">);</span>
    <span class="cp">`FAIL_UNLESS</span><span class="p">(</span><span class="n">intf</span><span class="p">.</span><span class="n">CYC_O</span> <span class="o">===</span> <span class="mi">1</span><span class="p">)</span>
    <span class="cp">`FAIL_UNLESS</span><span class="p">(</span><span class="n">intf</span><span class="p">.</span><span class="n">STB_O</span> <span class="o">===</span> <span class="mi">1</span><span class="p">)</span>
  <span class="cp">`SVTEST_END</span>

  <span class="c1">// ...</span>
<span class="k">endmodule</span>
</code></pre></div></div>

<p>Since <em>execute_item(…)</em> blocks until the driver finishes processing the item, we’ll need to fork it out to be able to check what the driver does with the it.</p>

<p>After supplying the driver with the item, we need to check that it drives the appropriate signal values. Once an item is gotten, we expect the driver to start driving <em>CYC_O</em> and <em>STB_O</em> and their values to be valid on the next posedge. We have to check one clock cycle at a time. For example, if we would drive an item with a delay of three cycles, the unit test would look like this:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">module</span> <span class="n">master_driver_unit_test</span><span class="p">;</span>

  <span class="cp">`SVTEST</span><span class="p">(</span><span class="n">cyc_and_stb_driven_with_delay</span><span class="p">)</span>
    <span class="n">sequence_item</span> <span class="n">item</span> <span class="o">=</span> <span class="k">new</span><span class="p">(</span><span class="s">"item"</span><span class="p">);</span>
    <span class="n">item</span><span class="p">.</span><span class="n">delay</span> <span class="o">=</span> <span class="mi">3</span><span class="p">;</span>

    <span class="k">fork</span>
      <span class="n">sequencer</span><span class="p">.</span><span class="n">execute_item</span><span class="p">(</span><span class="n">item</span><span class="p">);</span>
    <span class="k">join_none</span>

    <span class="kt">repeat</span> <span class="p">(</span><span class="mi">3</span><span class="p">)</span> <span class="k">begin</span>
      <span class="o">@</span><span class="p">(</span><span class="kt">posedge</span> <span class="n">clk</span><span class="p">);</span>
      <span class="cp">`FAIL_UNLESS</span><span class="p">(</span><span class="n">intf</span><span class="p">.</span><span class="n">CYC_O</span> <span class="o">===</span> <span class="mi">0</span><span class="p">)</span>
      <span class="cp">`FAIL_UNLESS</span><span class="p">(</span><span class="n">intf</span><span class="p">.</span><span class="n">STB_O</span> <span class="o">===</span> <span class="mi">0</span><span class="p">)</span>
    <span class="k">end</span>

    <span class="o">@</span><span class="p">(</span><span class="kt">posedge</span> <span class="n">clk</span><span class="p">);</span>
    <span class="cp">`FAIL_UNLESS</span><span class="p">(</span><span class="n">intf</span><span class="p">.</span><span class="n">CYC_O</span> <span class="o">===</span> <span class="mi">1</span><span class="p">)</span>
    <span class="cp">`FAIL_UNLESS</span><span class="p">(</span><span class="n">intf</span><span class="p">.</span><span class="n">STB_O</span> <span class="o">===</span> <span class="mi">1</span><span class="p">)</span>
  <span class="cp">`SVTEST_END</span>

  <span class="c1">// ...</span>
<span class="k">endmodule</span>
</code></pre></div></div>

<p>It’s not enough to just skip the first three clock cycles. We need to ensure that the driver signals idle cycles during that time. Also, notice the use of the <strong>===</strong> operator (4-state equality). If we were to use the <strong>==</strong> operator instead, we would get false positives if the driver doesn’t drive any of the signals. This is because <em>X</em> (unknown value due to not being driven) matches anything.</p>

<p>We could write a few more unit tests for our driver. For example, a test could check that a read transfer is properly driven:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">module</span> <span class="n">master_driver_unit_test</span><span class="p">;</span>

  <span class="cp">`SVTEST</span><span class="p">(</span><span class="n">read_transfer_driven</span><span class="p">)</span>
    <span class="n">sequence_item</span> <span class="n">item</span> <span class="o">=</span> <span class="k">new</span><span class="p">(</span><span class="s">"item"</span><span class="p">);</span>
    <span class="n">item</span><span class="p">.</span><span class="n">direction</span> <span class="o">=</span> <span class="n">READ</span><span class="p">;</span>
    <span class="n">item</span><span class="p">.</span><span class="n">address</span> <span class="o">=</span> <span class="mh">'haabb_ccdd</span><span class="p">;</span>

    <span class="k">fork</span>
      <span class="n">sequencer</span><span class="p">.</span><span class="n">execute_item</span><span class="p">(</span><span class="n">item</span><span class="p">);</span>
    <span class="k">join_none</span>

    <span class="o">@</span><span class="p">(</span><span class="kt">posedge</span> <span class="n">clk</span><span class="p">);</span>
    <span class="cp">`FAIL_UNLESS</span><span class="p">(</span><span class="n">intf</span><span class="p">.</span><span class="n">WE_O</span> <span class="o">===</span> <span class="mi">0</span><span class="p">)</span>
    <span class="cp">`FAIL_UNLESS</span><span class="p">(</span><span class="n">intf</span><span class="p">.</span><span class="n">ADR_O</span> <span class="o">===</span> <span class="mh">'haabb_ccdd</span><span class="p">)</span>
  <span class="cp">`SVTEST_END</span>

  <span class="c1">// ...</span>
<span class="k">endmodule</span>
</code></pre></div></div>

<p>Another test would check that a write transfer is properly driven:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">module</span> <span class="n">master_driver_unit_test</span><span class="p">;</span>

  <span class="cp">`SVTEST</span><span class="p">(</span><span class="n">write_transfer_driven</span><span class="p">)</span>
    <span class="n">sequence_item</span> <span class="n">item</span> <span class="o">=</span> <span class="k">new</span><span class="p">(</span><span class="s">"item"</span><span class="p">);</span>
    <span class="n">item</span><span class="p">.</span><span class="n">direction</span> <span class="o">=</span> <span class="n">WRITE</span><span class="p">;</span>
    <span class="n">item</span><span class="p">.</span><span class="n">address</span> <span class="o">=</span> <span class="mh">'h1122_3344</span><span class="p">;</span>

    <span class="k">fork</span>
      <span class="n">sequencer</span><span class="p">.</span><span class="n">execute_item</span><span class="p">(</span><span class="n">item</span><span class="p">);</span>
    <span class="k">join_none</span>

    <span class="o">@</span><span class="p">(</span><span class="kt">posedge</span> <span class="n">clk</span><span class="p">);</span>
    <span class="cp">`FAIL_UNLESS</span><span class="p">(</span><span class="n">intf</span><span class="p">.</span><span class="n">WE_O</span> <span class="o">===</span> <span class="mi">1</span><span class="p">)</span>
    <span class="cp">`FAIL_UNLESS</span><span class="p">(</span><span class="n">intf</span><span class="p">.</span><span class="n">ADR_O</span> <span class="o">===</span> <span class="mh">'h1122_3344</span><span class="p">)</span>
  <span class="cp">`SVTEST_END</span>

  <span class="c1">// ...</span>
<span class="k">endmodule</span>
</code></pre></div></div>

<p>Notice that in the last two tests we didn’t check <em>CYC_O</em> and <em>STB_O</em> anymore. This is because we already checked that they get driven when sending an item.  When we write the unit tests, we don’t write them in isolation from the production code. They evolve together. To save effort and make the tests more readable, we can focus on certain aspects of the class we want to test.</p>

<p>The implementation of the <em>drive()</em> task would look something like this:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">class</span> <span class="n">master_driver</span> <span class="k">extends</span> <span class="n">uvm_driver</span> <span class="p">#(</span><span class="n">sequence_item</span><span class="p">);</span>
  <span class="kt">virtual</span> <span class="k">protected</span> <span class="k">task</span> <span class="n">drive</span><span class="p">();</span>
    <span class="kt">repeat</span> <span class="p">(</span><span class="n">req</span><span class="p">.</span><span class="n">delay</span><span class="p">)</span>
      <span class="o">@</span><span class="p">(</span><span class="kt">posedge</span> <span class="n">intf</span><span class="p">.</span><span class="n">CLK_I</span><span class="p">);</span>

    <span class="n">intf</span><span class="p">.</span><span class="n">CYC_O</span> <span class="o">&lt;=</span> <span class="mi">1</span><span class="p">;</span>
    <span class="n">intf</span><span class="p">.</span><span class="n">STB_O</span> <span class="o">&lt;=</span> <span class="mi">1</span><span class="p">;</span>
    <span class="n">intf</span><span class="p">.</span><span class="n">WE_O</span> <span class="o">&lt;=</span> <span class="n">req</span><span class="p">.</span><span class="n">direction</span><span class="p">;</span>
    <span class="n">intf</span><span class="p">.</span><span class="n">ADR_O</span> <span class="o">&lt;=</span> <span class="n">req</span><span class="p">.</span><span class="n">address</span><span class="p">;</span>

    <span class="c1">// ...</span>
  <span class="k">endtask</span>

  <span class="c1">// ...</span>
<span class="k">endclass</span>
</code></pre></div></div>

<p>We can see that we drive <em>WE_O</em> and <em>ADR_O</em> at the same time we write <em>CYC_O</em> and <em>STB_O</em>. It wouldn’t bring us much if we, for example, exhaustively checked that the address can be driven with different delays.</p>

<p>Up to now we only tested that the driver properly reacts to requests from the sequencer. Most of the times, the driver also has to react to other events triggered by its partner on the bus. In our case, since we’re developing a master driver, it needs to be sensitive to toggles on signals driven by the slave. One such requirement is that a master is supposed to keep the control signals stable until the slave acknowledges the transfer. This is signaled by raising the <em>ACK_I</em> signal.</p>

<p>We need to write a test where, aside from executing an item on the sequencer, we also model the behavior of the slave:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">module</span> <span class="n">master_driver_unit_test</span><span class="p">;</span>

  <span class="cp">`SVTEST</span><span class="p">(</span><span class="n">transfer_held_until_ack</span><span class="p">)</span>
    <span class="n">sequence_item</span> <span class="n">item</span> <span class="o">=</span> <span class="k">new</span><span class="p">(</span><span class="s">"item"</span><span class="p">);</span>
    <span class="n">intf</span><span class="p">.</span><span class="n">ACK_I</span> <span class="o">&lt;=</span> <span class="mi">0</span><span class="p">;</span>

    <span class="k">fork</span>
      <span class="n">sequencer</span><span class="p">.</span><span class="n">execute_item</span><span class="p">(</span><span class="n">item</span><span class="p">);</span>
    <span class="k">join_none</span>

    <span class="kt">repeat</span> <span class="p">(</span><span class="mi">3</span><span class="p">)</span> <span class="k">begin</span>
      <span class="o">@</span><span class="p">(</span><span class="kt">posedge</span> <span class="n">clk</span><span class="p">);</span>
      <span class="cp">`FAIL_UNLESS</span><span class="p">(</span><span class="n">intf</span><span class="p">.</span><span class="n">CYC_O</span> <span class="o">===</span> <span class="mi">1</span><span class="p">)</span>
      <span class="cp">`FAIL_UNLESS</span><span class="p">(</span><span class="n">intf</span><span class="p">.</span><span class="n">STB_O</span> <span class="o">===</span> <span class="mi">1</span><span class="p">)</span>
    <span class="k">end</span>

    <span class="n">intf</span><span class="p">.</span><span class="n">ACK_I</span> <span class="o">&lt;=</span> <span class="mi">1</span><span class="p">;</span>
    <span class="o">@</span><span class="p">(</span><span class="kt">posedge</span> <span class="n">clk</span><span class="p">);</span>
    <span class="cp">`FAIL_UNLESS</span><span class="p">(</span><span class="n">intf</span><span class="p">.</span><span class="n">CYC_O</span> <span class="o">===</span> <span class="mi">1</span><span class="p">)</span>
    <span class="cp">`FAIL_UNLESS</span><span class="p">(</span><span class="n">intf</span><span class="p">.</span><span class="n">STB_O</span> <span class="o">===</span> <span class="mi">1</span><span class="p">)</span>
  <span class="cp">`SVTEST_END</span>

  <span class="c1">// ...</span>
<span class="k">endmodule</span>
</code></pre></div></div>

<p>We basically model all collaborators of the driver, where some might communicate with it via method calls (like the sequencer) and some might communicate with it via signal toggles on the interface (like a connected slave).</p>

<p>This last test would suggest that we should update the <em>drive()</em> task with the following code:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">class</span> <span class="n">master_driver</span> <span class="k">extends</span> <span class="n">uvm_driver</span> <span class="p">#(</span><span class="n">sequence_item</span><span class="p">);</span>
  <span class="kt">virtual</span> <span class="k">protected</span> <span class="k">task</span> <span class="n">drive</span><span class="p">();</span>
    <span class="c1">// ...</span>

    <span class="o">@</span><span class="p">(</span><span class="kt">posedge</span> <span class="n">intf</span><span class="p">.</span><span class="n">CLK_I</span> <span class="k">iff</span> <span class="n">intf</span><span class="p">.</span><span class="n">ACK_I</span><span class="p">);</span>
  <span class="k">endtask</span>

  <span class="c1">// ...</span>
<span class="k">endclass</span>
</code></pre></div></div>

<p>While this is what we would need to do, the test still passes without this line. This is because, once the driver starts driving an item, it won’t touch the signals anymore until it gets another item. The extra wait statement would cause the driver to mark an item as finished  at a later time. This is hints that it isn’t enough to just check signal toggles. It’s also important that the driver makes calls to <em>item_done()</em> at the right time. This isn’t something that we can check easily check with <em>uvm_sequencer</em>. We’d need to capture information about method calls from the driver to the sequencer.</p>

<p>We could choose to implement such extra testing functionality in a sub-class of <em>uvm_sequencer</em>. We could capture the number of times <em>item_done()</em> (or any other method) got called during a test. This wouldn’t be a problem to implement, but have you ever taken a look at <em>uvm_sequencer</em>? That class is massive. The functionality is shared with two of its subclasses, <em>uvm_sequencer_base</em> and <em>uvm_sequencer_param_base</em>. Most of the stuff a sequencer does (prioritization, locking, etc.) we don’t even need. Debugging anything would be a nightmare. Interrupting an item in the middle of it being driven (due to a unit test finishing early) is also going to cause fatal errors to be issued (e.g. “get_next_item() called twice without a call to item_done() in between”).</p>

<p>A better alternative would be to start from scratch with a lightweight class that mimics the <em>uvm_sequencer</em> functionality we need and provides us with test diagnostic information. When talking about test doubles, I like to use the same terminology as outlined in <a href="http://martinfowler.com/articles/mocksArentStubs.html#TheDifferenceBetweenMocksAndStubs">this article</a>. I can’t really decide whether what we want to create should be called a fake (since we’ll implement working functionality, but only a limited part of what <em>uvm_sequencer</em> can do) or a stub (since we want to collect information about method calls). I chose ‘stub’, for now, based on gut feeling.</p>

<p>Our stub has to be parameterizable, just like <em>uvm_sequencer</em>, to be able to interact with any driver. Just like a sequencer, it’s going to have a <em>seq_item_export</em> for the driver to connect to:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">class</span> <span class="n">sequencer_stub</span> <span class="p">#(</span><span class="k">type</span> <span class="n">REQ</span> <span class="o">=</span> <span class="n">uvm_sequence_item</span><span class="p">,</span> <span class="k">type</span> <span class="n">RSP</span> <span class="o">=</span> <span class="n">REQ</span><span class="p">)</span>
    <span class="k">extends</span> <span class="n">uvm_component</span><span class="p">;</span>

  <span class="n">uvm_seq_item_pull_imp</span> <span class="p">#(</span><span class="n">REQ</span><span class="p">,</span> <span class="n">RSP</span><span class="p">,</span> <span class="n">this_type</span><span class="p">)</span> <span class="n">seq_item_export</span><span class="p">;</span>

  <span class="c1">// ...</span>
<span class="k">endclass</span>
</code></pre></div></div>

<p>Since in every test we always forked out <em>execute_item(…)</em>, we’ll provide a function that just schedules an item to be picked up by the driver at its convenience:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">class</span> <span class="n">sequencer_stub</span> <span class="p">#(</span><span class="k">type</span> <span class="n">REQ</span> <span class="o">=</span> <span class="n">uvm_sequence_item</span><span class="p">,</span> <span class="k">type</span> <span class="n">RSP</span> <span class="o">=</span> <span class="n">REQ</span><span class="p">)</span>
    <span class="k">extends</span> <span class="n">uvm_component</span><span class="p">;</span>

  <span class="k">extern</span> <span class="kt">virtual</span> <span class="k">function</span> <span class="kt">void</span> <span class="n">add_item</span><span class="p">(</span><span class="n">REQ</span> <span class="n">item</span><span class="p">);</span>

  <span class="c1">// ...</span>
<span class="k">endclass</span>
</code></pre></div></div>

<p>Requests (items from the sequencer to the driver) and responses (items from the driver to the sequencer) will be stored in FIFOs:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">class</span> <span class="n">sequencer_stub</span> <span class="p">#(</span><span class="k">type</span> <span class="n">REQ</span> <span class="o">=</span> <span class="n">uvm_sequence_item</span><span class="p">,</span> <span class="k">type</span> <span class="n">RSP</span> <span class="o">=</span> <span class="n">REQ</span><span class="p">)</span>
    <span class="k">extends</span> <span class="n">uvm_component</span><span class="p">;</span>

  <span class="k">protected</span> <span class="n">uvm_tlm_fifo</span> <span class="p">#(</span><span class="n">REQ</span><span class="p">)</span> <span class="n">reqs</span><span class="p">;</span>
  <span class="k">protected</span> <span class="n">uvm_tlm_fifo</span> <span class="p">#(</span><span class="n">RSP</span><span class="p">)</span> <span class="n">rsps</span><span class="p">;</span>

  <span class="c1">// ...</span>
<span class="k">endclass</span>
</code></pre></div></div>

<p>Last, but not least, the sequencer methods (<em>get_next_item()</em>, <em>item_done(…)</em>, etc.) operate on these FIFOs to emulate the behavior of a real sequencer. For example, <em>get_next_item()</em> peeks inside the request FIFO:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">task</span> <span class="n">sequencer_stub</span><span class="o">::</span><span class="n">get_next_item</span><span class="p">(</span><span class="kt">output</span> <span class="n">REQ</span> <span class="n">t</span><span class="p">);</span>
  <span class="n">reqs</span><span class="p">.</span><span class="n">peek</span><span class="p">(</span><span class="n">t</span><span class="p">);</span>
<span class="k">endtask</span>
</code></pre></div></div>

<p>The <em>item_done(…)</em> function pops a request from the FIFO, because it’s been handled:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">function</span> <span class="kt">void</span> <span class="n">sequencer_stub</span><span class="o">::</span><span class="n">item_done</span><span class="p">(</span><span class="n">RSP</span> <span class="n">item</span> <span class="o">=</span> <span class="k">null</span><span class="p">);</span>
  <span class="n">REQ</span> <span class="n">t</span><span class="p">;</span>
  <span class="kt">void</span><span class="err">'</span><span class="p">(</span><span class="n">reqs</span><span class="p">.</span><span class="n">try_get</span><span class="p">(</span><span class="n">t</span><span class="p">));</span>

  <span class="c1">// ...</span>
<span class="k">endfunction</span>
</code></pre></div></div>

<p>At the same time, we can also count the number of times a certain method was called. This information could be useful to check that the driver requests items at defined intervals:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">function</span> <span class="kt">bit</span> <span class="n">sequencer_stub</span><span class="o">::</span><span class="n">has_do_available</span><span class="p">();</span>
  <span class="n">num_has_do_available_calls</span><span class="o">++</span><span class="p">;</span>
  <span class="k">return</span> <span class="o">!</span><span class="n">reqs</span><span class="p">.</span><span class="n">is_empty</span><span class="p">();</span>
<span class="k">endfunction</span>
</code></pre></div></div>

<p>Last, but not least, we’ll need to ensure that all unit tests start from the same state. This means that there aren’t any items queued from previous unit tests and that the diagnostic information has been cleared. A <em>flush()</em> method (similar to <em>uvm_tlm_fifo::flush()</em>) should be called in <em>teardown()</em> to enforce this rule:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">function</span> <span class="kt">void</span> <span class="n">sequencer_stub</span><span class="o">::</span><span class="n">flush</span><span class="p">();</span>
  <span class="n">reqs</span><span class="p">.</span><span class="n">flush</span><span class="p">();</span>
  <span class="n">rsps</span><span class="p">.</span><span class="n">flush</span><span class="p">();</span>
  <span class="n">num_get_next_item_calls</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
  <span class="n">num_try_next_item_calls</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
  <span class="c1">// ...</span>
<span class="k">endfunction</span>
</code></pre></div></div>

<p>We can replace the sequencer in our unit test with this <em>sequencer_stub</em> class:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">module</span> <span class="n">master_driver_unit_test</span><span class="p">;</span>
  <span class="n">sequencer_stub</span> <span class="p">#(</span><span class="n">sequence_item</span><span class="p">)</span> <span class="n">sequencer</span><span class="p">;</span>

  <span class="c1">// ...</span>
<span class="k">endmodule</span>
</code></pre></div></div>

<p>Replacing the calls to <em>execute_item(…)</em> with <em>add_item(…)</em> will make the code a bit more concise:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">module</span> <span class="n">master_driver_unit_test</span><span class="p">;</span>
  <span class="cp">`SVTEST</span><span class="p">(</span><span class="n">cyc_and_stb_driven</span><span class="p">)</span>
    <span class="n">sequence_item</span> <span class="n">item</span> <span class="o">=</span> <span class="k">new</span><span class="p">(</span><span class="s">"item"</span><span class="p">);</span>
    <span class="n">sequencer</span><span class="p">.</span><span class="n">add_item</span><span class="p">(</span><span class="n">item</span><span class="p">);</span>

    <span class="o">@</span><span class="p">(</span><span class="kt">posedge</span> <span class="n">clk</span><span class="p">);</span>
    <span class="cp">`FAIL_UNLESS</span><span class="p">(</span><span class="n">intf</span><span class="p">.</span><span class="n">CYC_O</span> <span class="o">===</span> <span class="mi">1</span><span class="p">)</span>
    <span class="cp">`FAIL_UNLESS</span><span class="p">(</span><span class="n">intf</span><span class="p">.</span><span class="n">STB_O</span> <span class="o">===</span> <span class="mi">1</span><span class="p">)</span>
  <span class="cp">`SVTEST_END</span>

  <span class="c1">// ...</span>
<span class="k">endmodule</span>
</code></pre></div></div>

<p>We could also do the more funky stuff, like testing that we only get a certain amount of calls to <em>item_done(…)</em> in a certain time window. Let’s skip this for now to keep the post short.</p>

<p>I’ve uploaded the code for the <em>sequencer_stub</em> to GitHub under the name <a href="https://github.com/tudortimi/vgm_svunit_utils">vgm_svunit_utils</a>. I’ll use this as an incubation area for additions to SVUnit. These could eventually get integrated into the main library if deemed to be worthy and useful to others.</p>

<p>You can also find the example code for this post <a href="https://github.com/verification-gentleman-blog/testing_uvm_drivers">here</a>. I hope it inspired you to give unit testing a try!</p>]]></content><author><name>Tudor Timi</name></author><category term="SVUnit" /><category term="SystemVerilog" /><category term="Unit testing" /><summary type="html"><![CDATA[It’s that time again when I’ve started a new project at work. Since we’re going to be using some new proprietary interfaces in this chip, this calls for some new UVCs. I wouldn’t even consider developing a new UVC without setting up a unit testing environment for it first. Since this is a greenfield project, a lot of the specifications are volatile, meaning that the interface protocol can change at any moment. Having tests in place can help make sure that I don’t miss anything. Even if the specification stays the same, I might decide to restructure the code and I want to be certain that it still works.]]></summary></entry><entry><title type="html">A Quick Look at SVAUnit</title><link href="https://blog.verificationgentleman.com/2016/07/24/a-quick-look-at-svaunit.html" rel="alternate" type="text/html" title="A Quick Look at SVAUnit" /><published>2016-07-24T17:05:00+02:00</published><updated>2016-07-24T17:05:00+02:00</updated><id>https://blog.verificationgentleman.com/2016/07/24/a-quick-look-at-svaunit</id><content type="html" xml:base="https://blog.verificationgentleman.com/2016/07/24/a-quick-look-at-svaunit.html"><![CDATA[<p>I’ve been writing more and more <em>SystemVerilog</em> assertions (SVAs) lately. I find that they are the best way to capture temporal requirements, allowing the rest of the (class-based) testbench to stay timing agnostic. Since assertions are a key part of the checking infrastructure we need to make sure that they’re bulletproof. This means that we need to test them to make sure that they’re doing what we expect them to do.</p>

<p>The typical flow when writing an assertion is the following (for me, at least):</p>

<ol>
  <li>write an assertion for some specific aspect</li>
  <li>check that the assertion fails in some desired scenario (for example, by doing forces)</li>
  <li>decide that it’s good enough and run a regression with the new assertion</li>
  <li>find out that it fails in some obscure corner case, where it really shouldn’t be checking at all</li>
  <li>patch assertion to avoid the false fail</li>
  <li>repeat from step 2 until getting a clean regression</li>
</ol>

<p>With each iteration where we modify the assertion, it could be the case that we break something. We might introduce new false negatives, that will be found out after after more iterations of the development loop. We might also introduce new false positives because we relax the assertion so much that it doesn’t check in all the cases it should. While the first one is bad because we take more time to finish, the second one is worse because we create gaps in our verification effort.</p>

<p>The main reason why something could get broken in the above process is because step 2 becomes so complicated, that we can’t realistically run all checks with each loop. A better way to develop assertions would be to implement step 2 in such a way that it’s repeatable so that it can be run after each change of the code. Basically, what that would mean is to write unit tests for the assertion.</p>

<p>The <a href="https://github.com/amiq-consulting/svaunit">SVAUnit</a> library from <a href="http://www.amiq.com/consulting/">AMIQ Consulting</a> was written to help developers write better assertions. I’ve been wanting to test drive it for a while and I finally got a chance. The first place to start is <a href="http://www.amiq.com/consulting/2015/04/29/how-to-verify-systemverilog-assertions-with-svaunit/">this article</a> on their blog, which contains a complete example. You could give it a read before going further with this post. We’ll basically follow the same steps as they did to set up and get a first test, but we’ll also do a few iterations of assertion refinement.</p>

<p>Our goal will be to write an assertion for the <a href="http://cdn.opencores.org/downloads/wbspec_b3.pdf">Wishbone protocol</a>. From the description of the handshake in Section 3.1.3 and from Rule 3.60, a requirement for a Wishbone master is that it has to hold ADR_O stable during a transfer, until it receives an acknowledge from the slave.</p>

<p>We’ll want to do test-driven development (TDD) of our property, which means we aren’t allowed to write any business code until we have a test that for it. The test is supposed to fail, to show that no code exists that fulfills its requirement. I think in the extreme case we wouldn’t even be allowed to write any production code, because a compile error is also a test error. We’ll skip this step and write an empty assertion:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">interface</span> <span class="n">vgm_wb_master_sva_checker</span><span class="p">(</span>
  <span class="kt">input</span> <span class="kt">bit</span> <span class="n">CLK_I</span><span class="p">,</span>
  <span class="kt">input</span> <span class="kt">bit</span> <span class="n">RST_I</span><span class="p">,</span>
  <span class="kt">input</span> <span class="kt">bit</span> <span class="n">CYC_O</span><span class="p">,</span>
  <span class="kt">input</span> <span class="kt">bit</span> <span class="n">STB_O</span><span class="p">,</span>
  <span class="kt">input</span> <span class="kt">bit</span><span class="p">[</span><span class="mi">31</span><span class="o">:</span><span class="mi">0</span><span class="p">]</span> <span class="n">ADR_O</span><span class="p">,</span>
  <span class="kt">input</span> <span class="kt">bit</span> <span class="n">ACK_I</span>
<span class="p">);</span>
  <span class="k">default</span> <span class="k">clocking</span> <span class="n">cb</span> <span class="o">@</span><span class="p">(</span><span class="kt">posedge</span> <span class="n">CLK_I</span><span class="p">);</span>
  <span class="k">endclocking</span>

  <span class="k">default</span> <span class="kt">disable</span> <span class="k">iff</span> <span class="n">RST_I</span><span class="p">;</span>


  <span class="n">ADR_HELD_UNTIL_ACK</span> <span class="o">:</span> <span class="k">assert</span> <span class="k">property</span> <span class="p">(</span>
    <span class="o">!</span><span class="n">CLK_I</span> <span class="o">|-&gt;</span> <span class="mi">1</span>  <span class="c1">// Something that never matches</span>
  <span class="p">);</span>
<span class="k">endinterface</span>
</code></pre></div></div>

<p>I like to separate SVA checkers from the interface used by an agent for driving and monitoring. Because we only use input signals, we avoid any subtle bugs related to driving both from the agent and from some buggy assertion or assertion support code (e.g. using <code class="language-plaintext highlighter-rouge">=</code> instead of <code class="language-plaintext highlighter-rouge">==</code>). Ideally, instead of using an <strong>interface</strong> we would use a <strong>checker</strong> (which by definition can only have inputs), but tool support for this language construct is rather sparse. I avoided writing an assertion that trivially passes on every clock cycle, because that would cause tests of the form “assertion succeeds if …” to pass, even though the code doesn’t really do anything. I guess what we write here at this point isn’t really that important, but from a purist point of view, it seems that an assertion that never starts is a better choice.</p>

<p>Now that we have our SVA checker, it’s time to set up our testing infrastructure. SVAUnit is built on UVM. Tests are class-based, so they need a virtual interface to be able to stimulate the SVA checkers inputs. We’ll need another interface with internal signals that can be driven by the tests:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">interface</span> <span class="n">wb_bfm</span><span class="p">();</span>
  <span class="kt">bit</span> <span class="n">CLK</span><span class="p">;</span>
  <span class="kt">bit</span> <span class="n">RST</span><span class="p">;</span>
  <span class="kt">bit</span> <span class="n">CYC</span><span class="p">;</span>
  <span class="kt">bit</span> <span class="n">STB</span><span class="p">;</span>
  <span class="kt">bit</span><span class="p">[</span><span class="mi">31</span><span class="o">:</span><span class="mi">0</span><span class="p">]</span> <span class="n">ADR</span><span class="p">;</span>
  <span class="kt">bit</span> <span class="n">ACK</span><span class="p">;</span>

  <span class="k">clocking</span> <span class="n">cb</span> <span class="o">@</span><span class="p">(</span><span class="kt">posedge</span> <span class="n">CLK</span><span class="p">);</span>
  <span class="k">endclocking</span>

  <span class="k">always</span> <span class="p">#</span><span class="mi">1</span> <span class="n">CLK</span> <span class="o">=</span> <span class="o">~</span><span class="n">CLK</span><span class="p">;</span>
<span class="k">endinterface</span>
</code></pre></div></div>

<p>All of our unit tests will need need to use this second interface. Since the tests are all classes, we can declare a base class for them that handles the infrastructural aspect of getting the virtual interface:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">class</span> <span class="n">test_base</span> <span class="k">extends</span> <span class="n">svaunit_test</span><span class="p">;</span>
  <span class="kt">virtual</span> <span class="n">wb_bfm</span> <span class="n">bfm</span><span class="p">;</span>


  <span class="k">function</span> <span class="kt">void</span> <span class="n">build_phase</span><span class="p">(</span><span class="kt">input</span> <span class="n">uvm_phase</span> <span class="n">phase</span><span class="p">);</span>
    <span class="k">super</span><span class="p">.</span><span class="n">build_phase</span><span class="p">(</span><span class="n">phase</span><span class="p">);</span>

    <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">uvm_config_db</span> <span class="p">#(</span><span class="kt">virtual</span> <span class="n">wb_bfm</span><span class="p">)</span><span class="o">::</span><span class="n">get</span><span class="p">(</span><span class="k">null</span><span class="p">,</span> <span class="s">"*"</span><span class="p">,</span> <span class="s">"bfm"</span><span class="p">,</span> <span class="n">bfm</span><span class="p">))</span>
      <span class="cp">`uvm_fatal</span><span class="p">(</span><span class="s">"BFMERR"</span><span class="p">,</span> <span class="s">"BFM wasn't passed"</span><span class="p">);</span>
  <span class="k">endfunction</span>

  <span class="c1">// ...</span>
<span class="k">endclass</span>
</code></pre></div></div>

<p>Let’s write a first test that should cause the assertion to fail:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">class</span> <span class="n">adr_held_until_ack_fail</span> <span class="k">extends</span> <span class="n">test_base</span><span class="p">;</span>
  <span class="k">task</span> <span class="n">test</span><span class="p">();</span>
    <span class="n">bfm</span><span class="p">.</span><span class="n">CYC</span> <span class="o">&lt;=</span> <span class="mi">1</span><span class="p">;</span>
    <span class="n">bfm</span><span class="p">.</span><span class="n">STB</span> <span class="o">&lt;=</span> <span class="mi">1</span><span class="p">;</span>
    <span class="n">bfm</span><span class="p">.</span><span class="n">ADR</span> <span class="o">&lt;=</span> <span class="mh">'h1122_3344</span><span class="p">;</span>
    <span class="o">@</span><span class="p">(</span><span class="n">bfm</span><span class="p">.</span><span class="n">cb</span><span class="p">);</span>

    <span class="n">bfm</span><span class="p">.</span><span class="n">ADR</span> <span class="o">&lt;=</span> <span class="mh">'hffff_0000</span><span class="p">;</span>
    <span class="o">@</span><span class="p">(</span><span class="n">bfm</span><span class="p">.</span><span class="n">cb</span><span class="p">);</span>

    <span class="cp">`pass_if_sva_not_succeeded</span><span class="p">(</span><span class="s">"ADR_HELD_UNTIL_ACK"</span><span class="p">,</span> <span class="s">""</span><span class="p">)</span>
  <span class="k">endtask</span>

  <span class="c1">// ...</span>
<span class="k">endclass</span>
</code></pre></div></div>

<p>Initially I had the crazy idea of using the <code class="language-plaintext highlighter-rouge">`fail_sva_succeeded(...)</code> macro, but that’s not really the same thing as testing for a pass. That an assertion didn’t fail is a necessary condition for it to pass, but it’s not sufficient. It also needs to have triggered and finished.</p>

<p>The business code of a unit test should be placed inside the <em>test()</em> task, which will be run by the framework. In this case, we start driving a transfer to address <em>0x1122_3344</em>, but we change the address in the next cycle, before the slave has a chance to respond.</p>

<p>We’ll need to tell the SVAUnit framework which tests to run. This is done in a test suite:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">class</span> <span class="n">test_suite</span> <span class="k">extends</span> <span class="n">svaunit_test_suite</span><span class="p">;</span>
  <span class="k">function</span> <span class="kt">void</span> <span class="n">build_phase</span><span class="p">(</span><span class="n">uvm_phase</span> <span class="n">phase</span><span class="p">);</span>
    <span class="k">super</span><span class="p">.</span><span class="n">build_phase</span><span class="p">(</span><span class="n">phase</span><span class="p">);</span>

    <span class="cp">`add_test</span><span class="p">(</span><span class="n">adr_held_until_ack_fail</span><span class="p">)</span>
  <span class="k">endfunction</span>

  <span class="c1">// ...</span>
<span class="k">endclass</span>
</code></pre></div></div>

<p>The final piece of the infrastructure is a top module that connects the two interfaces and triggers execution of the unit tests:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">module</span> <span class="n">top</span><span class="p">;</span>
  <span class="cp">`SVAUNIT_UTILS</span>

  <span class="cp">`include</span> <span class="s">"test_base.svh"</span>
  <span class="cp">`include</span> <span class="s">"tests/adr_held_until_ack_fail.svh"</span>
  <span class="cp">`include</span> <span class="s">"test_suite.svh"</span>


  <span class="n">wb_bfm</span> <span class="n">bfm</span><span class="p">();</span>
  <span class="n">vgm_wb_master_sva_checker</span> <span class="n">intf</span><span class="p">(</span>
    <span class="n">bfm</span><span class="p">.</span><span class="n">CLK</span><span class="p">,</span>
    <span class="n">bfm</span><span class="p">.</span><span class="n">RST</span><span class="p">,</span>
    <span class="n">bfm</span><span class="p">.</span><span class="n">CYC</span><span class="p">,</span>
    <span class="n">bfm</span><span class="p">.</span><span class="n">STB</span><span class="p">,</span>
    <span class="n">bfm</span><span class="p">.</span><span class="n">ADR</span><span class="p">,</span>
    <span class="n">bfm</span><span class="p">.</span><span class="n">ACK</span>
  <span class="p">);</span>


  <span class="k">initial</span> <span class="k">begin</span>
    <span class="n">uvm_config_db</span> <span class="p">#(</span><span class="kt">virtual</span> <span class="n">wb_bfm</span><span class="p">)</span><span class="o">::</span><span class="n">set</span><span class="p">(</span><span class="k">null</span><span class="p">,</span> <span class="s">"*"</span><span class="p">,</span> <span class="s">"bfm"</span><span class="p">,</span> <span class="n">bfm</span><span class="p">);</span>
    <span class="n">run_test</span><span class="p">();</span>
  <span class="k">end</span>
<span class="k">endmodule</span>
</code></pre></div></div>

<p>Now it’s time to run our unit test. Since we didn’t implement anything in our assertion yet, the test should fail. After starting the run, I found that the reports are way to verbose. In comparison to the lightweight PASS/FAIL information you get from SVUnit, for just one unit test SVAUnit prints quite a few lines.</p>

<p>At first, I got a misleading error message that the assertion is not enabled. I didn’t really know how to interpret this. I thought it had something to do with the fact that the assertion can’t trigger (since I wrote it like this). I made it trigger, but the message was still there. After digging around through the library code, I saw that an assertion has to be explicitly tagged as an assertion-under-test. It wasn’t obvious from the documentation that this is required, so I think this is something that needs to be improved.</p>

<p>I figured the best place to do that would be in the <em>pre_test()</em> method:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">class</span> <span class="n">test_base</span> <span class="k">extends</span> <span class="n">svaunit_test</span><span class="p">;</span>
  <span class="k">task</span> <span class="n">pre_test</span><span class="p">();</span>
    <span class="n">vpiw</span><span class="p">.</span><span class="n">enable_assertion</span><span class="p">(</span><span class="s">"ADR_HELD_UNTIL_ACK"</span><span class="p">);</span>
  <span class="k">endtask</span>

  <span class="c1">// ...</span>
<span class="k">endclass</span>
</code></pre></div></div>

<p>I did this, but nothing changed. After some more digging around, it seems that the <em>pre_test()</em> method never gets executed. This somehow contradicts their blog article and their CDNLive paper. It seems that there was a change in the code at one point and the documentation lagged behind. To get this working, I called <em>pre_test()</em> from the test’s <em>run()</em> task:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">class</span> <span class="n">adr_held_until_ack_fail</span> <span class="k">extends</span> <span class="n">test_base</span><span class="p">;</span>
  <span class="k">task</span> <span class="n">test</span><span class="p">();</span>
    <span class="n">pre_test</span><span class="p">();</span>
    <span class="c1">// ...</span>
  <span class="k">endtask</span>

  <span class="c1">// ...</span>
<span class="k">endclass</span>
</code></pre></div></div>

<p>Having gotten used to SVUnit’s <em>setup()</em> and <em>teardown()</em> methods (which are taken from JUnit), I’m disappointed that something similar doesn’t exist here.</p>

<p>The reports use some muddled terminology. They say that “x/y assertions PASSED”. This was confusing, since I had only written one assertion. SVAUnit also calls its checks “assertions”. This is a poor choice of wording for a framework that is supposed to test assertions.</p>

<p>Toward the end of the report there is a section that mentions that not all checks were exercised. For example, we haven’t tried running a test where we expect the assertion to pass. This is a bit too verbose for my taste, since we, as users, should be able to decide what kinds of tests we want to run. We might decide that we don’t want to do any pass testing, since any false fails will be caught when running an assertion together with the DUT. These messages are informative and don’t affect the result of a test suite run.</p>

<p>In any case, we should now see that the test is failing, as we expected. Moving on with TDD, we want to write the least amount of code that will get this test to pass. Again, if we want to be purists about it, we can write the following implementation for the assertion:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="n">ADR_HELD_UNTIL_ACK</span> <span class="o">:</span> <span class="k">assert</span> <span class="k">property</span> <span class="p">(</span>
    <span class="mi">0</span>
  <span class="p">);</span>
</code></pre></div></div>

<p>This assertion always fails, but it doesn’t do what we want it to do. We also want it to pass whenever a master keeps the address stable. For this new requirement, we can write a second unit test:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">class</span> <span class="n">adr_held_until_ack_pass</span> <span class="k">extends</span> <span class="n">test_base</span><span class="p">;</span>
  <span class="k">task</span> <span class="n">test</span><span class="p">();</span>
    <span class="n">pre_test</span><span class="p">();</span>

    <span class="n">bfm</span><span class="p">.</span><span class="n">CYC</span> <span class="o">&lt;=</span> <span class="mi">1</span><span class="p">;</span>
    <span class="n">bfm</span><span class="p">.</span><span class="n">STB</span> <span class="o">&lt;=</span> <span class="mi">1</span><span class="p">;</span>
    <span class="n">bfm</span><span class="p">.</span><span class="n">ADR</span> <span class="o">&lt;=</span> <span class="mh">'h1122_3344</span><span class="p">;</span>
    <span class="o">@</span><span class="p">(</span><span class="n">bfm</span><span class="p">.</span><span class="n">cb</span><span class="p">);</span>

    <span class="n">bfm</span><span class="p">.</span><span class="n">ACK</span> <span class="o">&lt;=</span> <span class="mi">1</span><span class="p">;</span>
    <span class="o">@</span><span class="p">(</span><span class="n">bfm</span><span class="p">.</span><span class="n">cb</span><span class="p">);</span>

    <span class="p">#</span><span class="mi">1</span><span class="p">;</span>
    <span class="cp">`pass_if_sva_succeeded</span><span class="p">(</span><span class="s">"ADR_HELD_UNTIL_ACK"</span><span class="p">,</span> <span class="s">""</span><span class="p">)</span>
  <span class="k">endtask</span>

  <span class="c1">// ...</span>
<span class="k">endclass</span>
</code></pre></div></div>

<p>Now we’ll need to get our hands dirty and write some real code for the assertion:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="n">ADR_HELD_UNTIL_ACK</span> <span class="o">:</span> <span class="k">assert</span> <span class="k">property</span> <span class="p">(</span>
    <span class="n">CYC_O</span> <span class="o">&amp;&amp;</span> <span class="n">STB_O</span> <span class="o">|=&gt;</span>
      <span class="n">ADR_O</span> <span class="o">==</span> <span class="p">$</span><span class="nb">past</span><span class="p">(</span><span class="n">ADR_O</span><span class="p">)</span> <span class="k">throughout</span> <span class="n">ACK_I</span> <span class="p">[</span><span class="o">-&gt;</span><span class="mi">1</span><span class="p">]</span>
  <span class="p">);</span>
</code></pre></div></div>

<p>We can argue about whether this is the minimum amount of code that causes the test to pass (hint: it’s not). Nevertheless, this implementation passes both tests. Our job is done! Or is it?…</p>

<p>You might have noticed that the assertion requires at least two cycles to determine its result, because of the <code class="language-plaintext highlighter-rouge">|=&gt;</code> operator. This implies that Wishbone transfers always take at least two cycles. According to Permission 3.30 and Permission 3.35, this isn’t necessarily the case, as a slave could immediately respond to a transfer. This is something we discovered by review now, but it could have been the case that we would have seen some fails in the regression that would have been marked as being false. What do we have to do in this case? We need to relax the assertion.</p>

<p>The first thing we need is to write a test that causes a false fail. For example, we could have two back-to-back transfers, where the first one is finished without any wait states:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">class</span> <span class="n">adr_held_until_ack_pass_b2b_no_wait</span> <span class="k">extends</span> <span class="n">test_base</span><span class="p">;</span>
  <span class="k">task</span> <span class="n">test</span><span class="p">();</span>
    <span class="n">pre_test</span><span class="p">();</span>

    <span class="n">bfm</span><span class="p">.</span><span class="n">CYC</span> <span class="o">&lt;=</span> <span class="mi">1</span><span class="p">;</span>
    <span class="n">bfm</span><span class="p">.</span><span class="n">STB</span> <span class="o">&lt;=</span> <span class="mi">1</span><span class="p">;</span>
    <span class="n">bfm</span><span class="p">.</span><span class="n">ADR</span> <span class="o">&lt;=</span> <span class="mh">'h1122_3344</span><span class="p">;</span>
    <span class="n">bfm</span><span class="p">.</span><span class="n">ACK</span> <span class="o">&lt;=</span> <span class="mi">1</span><span class="p">;</span>
    <span class="o">@</span><span class="p">(</span><span class="n">bfm</span><span class="p">.</span><span class="n">cb</span><span class="p">);</span>

    <span class="n">bfm</span><span class="p">.</span><span class="n">ADR</span> <span class="o">&lt;=</span> <span class="mh">'hffff_0000</span><span class="p">;</span>
    <span class="o">@</span><span class="p">(</span><span class="n">bfm</span><span class="p">.</span><span class="n">cb</span><span class="p">);</span>

    <span class="cp">`fail_if_sva_not_succeeded</span><span class="p">(</span><span class="s">"ADR_HELD_UNTIL_ACK"</span><span class="p">,</span> <span class="s">""</span><span class="p">)</span>
  <span class="k">endtask</span>

  <span class="c1">// ...</span>
<span class="k">endclass</span>
</code></pre></div></div>

<p>Once we have a test, we can also fix the assertion:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="n">ADR_HELD_UNTIL_ACK</span> <span class="o">:</span> <span class="k">assert</span> <span class="k">property</span> <span class="p">(</span>
    <span class="n">CYC_O</span> <span class="o">&amp;&amp;</span> <span class="n">STB_O</span> <span class="o">|-&gt;</span>
      <span class="n">ACK_I</span> <span class="kt">or</span>
        <span class="p">##</span><span class="mi">1</span> <span class="p">(</span><span class="n">ADR_O</span> <span class="o">==</span> <span class="p">$</span><span class="nb">past</span><span class="p">(</span><span class="n">ADR_O</span><span class="p">)</span> <span class="k">throughout</span> <span class="n">ACK_I</span> <span class="p">[</span><span class="o">-&gt;</span><span class="mi">1</span><span class="p">])</span>
  <span class="p">);</span>
</code></pre></div></div>

<p>As mentioned in the beginning, this is the point of highest risk, because we could relax the assertion in such a way that it never fails. Because our previous unit tests still pass, we know we still fulfill the old requirements.</p>

<p>Notice that we didn’t say that the assertion has to pass. Because it’s enough that it doesn’t fail, we can even refactor it to not trigger in the case of a transfer without any wait cycles:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="n">ADR_HELD_UNTIL_ACK</span> <span class="o">:</span> <span class="k">assert</span> <span class="k">property</span> <span class="p">(</span>
    <span class="n">CYC_O</span> <span class="o">&amp;&amp;</span> <span class="n">STB_O</span> <span class="o">&amp;&amp;</span> <span class="o">!</span><span class="n">ACK_I</span> <span class="o">|=&gt;</span>
      <span class="n">ADR_O</span> <span class="o">==</span> <span class="p">$</span><span class="nb">past</span><span class="p">(</span><span class="n">ADR_O</span><span class="p">)</span> <span class="k">throughout</span> <span class="n">ACK_I</span> <span class="p">[</span><span class="o">-&gt;</span><span class="mi">1</span><span class="p">]</span>
  <span class="p">);</span>
</code></pre></div></div>

<p>It all depends on what our requirements are. If we want the assertion to only check in case of stalled transfers, then we should really use <code class="language-plaintext highlighter-rouge">pass_if_sva_not_started(...)</code>. In that case, we wouldn’t even need the second back-to-back transfer in our test.</p>

<p>I’ve uploaded the example code to <a href="https://github.com/verification-gentleman-blog/svaunit_sandbox">GitHub</a> for anyone who wants to tinker with it. I’ve changed the packaging to have one repository per example. I think this is better, because it allows me to deliver in smaller chunks, which should hopefully be easier to read/understand/modify. I’ll also try to release the old examples in this format and update the corresponding pages.</p>

<p>After this short TDD tutorial, let’s get back to SVAUnit unit itself. The ‘one test per class’ idea seems nice at first. We can have each test in its own file and that can make things more bite-sized. At the same time, because tests need to be <em>svaunit_tests</em>, we need to provide a constructor for each and everyone of them, which can result in a lot of boilerplate. The <code class="language-plaintext highlighter-rouge">add_test(...)</code> macro also tries to create tests using the factory, so we’ll need to implement registration, too. The idea of creating unit tests via the UVM factory is a bit stretched, since I don’t see any situation where being able to do overrides would be useful (and if you do want to use this, it sounds like you’re overthinking things).</p>

<p>I find the entire decision to base the package on UVM a bit much, since it adds unneeded complexity. SVAUnit could have defined its own idioms for building and running tests. It might also put off the non-UVM crowd, like people still using directed testing or formal verification engineers. Some might see UVM in there and say “for sure it’s gonna be complicated, I’ll just continue doing my own thing”. The only good reason to use UVM (that I got from Ionuț Ciocîrlan, one of the developers, in a hallway discussion last year) was that you could plug UVCs into the testing infrastructure for the stimulus generation. In our example, if we would have had a Wishbone UVC, we wouldn’t have had to write all of the signal toggles by ourselves, but just start transactions on a Wishbone driver/sequencer pair. This could be pretty useful for complicated protocols. Even so, it should be possible to integrate UVCs into non-UVM environments with a certain amount of effort. A UVM-based SVAunit only makes it easier to do so; it doesn’t turn it from impossible to possible.</p>

<p>Another comment I have is that it’s not enough to check if an assertion passed or failed. There are cases where we would want to check how many times an assertion passed or failed. This would be useful when we would want to make sure that assertions don’t start multiple parallel threads.</p>

<p>All and all, the library is a bit rough around the edges. It wasn’t easy for me as a beginner to start using it. The examples provided with the installation are way too complicated. I would have found it much better if they would have included the code from the blog post as a standalone example. This would have made it easier to follow. Once you get used to it, though, it’s easy to get productive. Barring some qualms about the not-so-up-to-date documentation, setup and teardown, required boilerplate code and the heavyweight reporting (which can be customized since it’s UVM), all which are things that can be easily fixed, SVAUnit is pretty solid.</p>

<p>For now, though, I prefer using SVUnit. I already use it to develop my classes and I don’t want to fragment my unit testing across two different frameworks. I have some rudimentary VPI code that lets me get the status of assertions and I can achieve pretty much the same basic functionality as with SVAUnit. Nevertheless, if you’re not doing any unit testing at all, you could start with your assertions. You probably already do a lot of ad hoc testing via forces or RTL code mutation, so why not formalize that and make it repeatable using SVAUnit?</p>]]></content><author><name>Tudor Timi</name></author><category term="Software development" /><category term="SystemVerilog" /><summary type="html"><![CDATA[I’ve been writing more and more SystemVerilog assertions (SVAs) lately. I find that they are the best way to capture temporal requirements, allowing the rest of the (class-based) testbench to stay timing agnostic. Since assertions are a key part of the checking infrastructure we need to make sure that they’re bulletproof. This means that we need to test them to make sure that they’re doing what we expect them to do.]]></summary></entry><entry><title type="html">The Humble Beginnings of a SystemVerilog Reflection API, Part 3</title><link href="https://blog.verificationgentleman.com/2016/06/01/systemverilog-reflection-api-part3.html" rel="alternate" type="text/html" title="The Humble Beginnings of a SystemVerilog Reflection API, Part 3" /><published>2016-06-01T22:59:00+02:00</published><updated>2016-06-01T22:59:00+02:00</updated><id>https://blog.verificationgentleman.com/2016/06/01/systemverilog-reflection-api-part3</id><content type="html" xml:base="https://blog.verificationgentleman.com/2016/06/01/systemverilog-reflection-api-part3.html"><![CDATA[<p>We’ve already looked at how to <a href="/2016/04/10/systemverilog-reflection-api.html">interrogate classes</a> about what variables they have and how to <a href="/2016/05/20/systemverilog-reflection-api-part2.html">set and get</a> the values of these variables in different instances. Classes are much more than just data containers, though. They also contain methods that can operate on their variables. In this post we’ll look at how we can handle tasks and functions inside our reflection API.</p>

<p>Before we start, however, let’s take a quick look at the two kinds of methods we can declare in <em>SystemVerilog</em>: <strong>tasks</strong> and <strong>functions</strong>. Both allow the caller to pass information to the method via arguments. Functions can also return a value when the call is finished, but must do this without consuming any simulation time. Tasks can, on the other hand, advance time, but they can’t return anything.</p>

<p>Because both have some similarities, it makes sense to model them using a common class, <em>rf_method</em>. This class will handle queries regarding a method’s arguments:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">virtual</span> <span class="kt">class</span> <span class="n">rf_method</span><span class="p">;</span>
  <span class="k">extern</span> <span class="k">function</span> <span class="kt">string</span> <span class="n">get_name</span><span class="p">();</span>
  <span class="k">extern</span> <span class="k">function</span> <span class="n">method_kind_e</span> <span class="n">get_kind</span><span class="p">();</span>

  <span class="k">extern</span> <span class="k">function</span> <span class="n">array_of_rf_io_declaration</span> <span class="n">get_io_declarations</span><span class="p">();</span>
  <span class="k">extern</span> <span class="k">function</span> <span class="n">rf_io_declaration</span> <span class="n">get_io_declaration_by_name</span><span class="p">(</span><span class="kt">string</span> <span class="n">name</span><span class="p">);</span>

  <span class="c1">// ...</span>
<span class="k">endclass</span>
</code></pre></div></div>

<p>The VPI section of the standard uses the term “IO declaration” for a method’s arguments. This is because, as for module and interface ports, an argument can be an <strong>input</strong>, an <strong>output</strong> or an <strong>inout</strong>. We’ll need another class to handle IO declaration:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">class</span> <span class="n">rf_io_declaration</span><span class="p">;</span>
  <span class="k">extern</span> <span class="k">function</span> <span class="kt">string</span> <span class="n">get_name</span><span class="p">();</span>
  <span class="k">extern</span> <span class="k">function</span> <span class="kt">string</span> <span class="n">get_type</span><span class="p">();</span>
  <span class="k">extern</span> <span class="k">function</span> <span class="n">io_direction_e</span> <span class="n">get_direction</span><span class="p">();</span>

  <span class="c1">// ...</span>
<span class="k">endclass</span>
</code></pre></div></div>

<p>Given a <em>vpiHandle</em> that points to an IO declaration, it’s easy to extract its direction:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">typedef</span> <span class="kt">enum</span> <span class="o">{</span> <span class="n">INPUT</span><span class="p">,</span> <span class="n">OUTPUT</span><span class="p">,</span> <span class="n">INOUT</span> <span class="o">}</span> <span class="n">io_direction_e</span><span class="p">;</span>

<span class="k">function</span> <span class="n">io_direction_e</span> <span class="n">rf_io_declaration</span><span class="o">::</span><span class="n">get_direction</span><span class="p">();</span>
  <span class="k">case</span> <span class="p">(</span><span class="n">vpi_get</span><span class="p">(</span><span class="n">vpiDirection</span><span class="p">,</span> <span class="n">io_declaration</span><span class="p">))</span>
    <span class="n">vpiInput</span> <span class="o">:</span> <span class="k">return</span> <span class="n">INPUT</span><span class="p">;</span>
    <span class="n">vpiOutput</span> <span class="o">:</span> <span class="k">return</span> <span class="n">OUTPUT</span><span class="p">;</span>
    <span class="n">vpiInout</span> <span class="o">:</span> <span class="k">return</span> <span class="n">INOUT</span><span class="p">;</span>
    <span class="k">default</span> <span class="o">:</span> <span class="p">$</span><span class="n">fatal</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="s">"Direction %s not supported"</span><span class="p">,</span> <span class="n">vpi_get_str</span><span class="p">(</span><span class="n">vpiDirection</span><span class="p">,</span>
      <span class="n">io_declaration</span><span class="p">));</span>
  <span class="k">endcase</span>
<span class="k">endfunction</span>
</code></pre></div></div>

<p>To extract the type of an IO declaration, we can treat it as any normal variable. This means that we can use the <em>rf_variable</em> class’s <em>get_type()</em> function to provide us with this information:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">function</span> <span class="kt">string</span> <span class="n">rf_io_declaration</span><span class="o">::</span><span class="n">get_type</span><span class="p">();</span>
  <span class="n">rf_variable</span> <span class="n">v</span> <span class="o">=</span> <span class="k">new</span><span class="p">(</span><span class="n">vpi_handle</span><span class="p">(</span><span class="n">vpiExpr</span><span class="p">,</span> <span class="n">io_declaration</span><span class="p">));</span>
  <span class="k">return</span> <span class="n">v</span><span class="p">.</span><span class="n">get_type</span><span class="p">();</span>
<span class="k">endfunction</span>
</code></pre></div></div>

<p>Looping over a method’s IO declaration is done in basically the same way as when going through variables, so we’ll skip over that code.</p>

<p>Now that we’ve handle the similarities between <strong>tasks</strong> and <strong>functions</strong>, it’s time to look at their differences. In terms of properties we can express through code, tasks don’t provide anything more. This means that the <em>rf_task</em> class doesn’t have to do anything special:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">class</span> <span class="n">rf_task</span> <span class="k">extends</span> <span class="n">rf_method</span><span class="p">;</span>
  <span class="k">function</span> <span class="k">new</span><span class="p">(</span><span class="n">vpiHandle</span> <span class="n">method</span><span class="p">);</span>
    <span class="k">super</span><span class="p">.</span><span class="k">new</span><span class="p">(</span><span class="n">method</span><span class="p">);</span>
  <span class="k">endfunction</span>
<span class="k">endclass</span>
</code></pre></div></div>

<p>We’ll still define this class, because the <em>rf_method</em> class is <strong>virtual</strong> (meaning that we don’t want to instantiate it directly). It also makes our API future-proof, if anything is added to tasks later.</p>

<p>Functions have a return type, which we would like to be able to interrogate. The <em>rf_function</em> class let’s us do this:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">class</span> <span class="n">rf_function</span> <span class="k">extends</span> <span class="n">rf_method</span><span class="p">;</span>
  <span class="k">extern</span> <span class="k">function</span> <span class="kt">string</span> <span class="n">get_return_type</span><span class="p">();</span>

  <span class="c1">// ...</span>
<span class="k">endclass</span>
</code></pre></div></div>

<p>As for method arguments, we can treat the return of a function as a variable and use the <em>rf_variable</em> class to get its type:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">function</span> <span class="kt">string</span> <span class="n">rf_function</span><span class="o">::</span><span class="n">get_return_type</span><span class="p">();</span>
  <span class="n">vpiHandle</span> <span class="n">r</span> <span class="o">=</span> <span class="n">vpi_handle</span><span class="p">(</span><span class="n">vpiReturn</span><span class="p">,</span> <span class="n">method</span><span class="p">);</span>
  <span class="n">rf_variable</span> <span class="n">v</span><span class="p">;</span>
  <span class="k">if</span> <span class="p">(</span><span class="n">r</span> <span class="o">==</span> <span class="k">null</span><span class="p">)</span>
    <span class="k">return</span> <span class="s">"void"</span><span class="p">;</span>
  <span class="n">v</span> <span class="o">=</span> <span class="k">new</span><span class="p">(</span><span class="n">r</span><span class="p">);</span>
  <span class="k">return</span> <span class="n">v</span><span class="p">.</span><span class="n">get_type</span><span class="p">();</span>
<span class="k">endfunction</span>
</code></pre></div></div>

<p>These were the basic things we could extract about tasks and functions. Other interesting properties would be whether they are <strong>local</strong>, <strong>protected</strong> or public, whether they are <strong>virtual</strong> and so on, but we won’t look at this here. These could be added to <em>rf_method</em> later.</p>

<p>As we said when we talked about variables, being able to interrogate the structure of declared methods only means that we’ve implemented introspection. Full reflection in this respect requires us to be able to call the methods of any object. Unfortunately, I couldn’t find anything in the VPI chapter about how to do this, so it it seems that this might not be possible. Oh well, we were bound to be disappointed eventually…</p>

<p>Even though it’s not possible to call functions, I can imagine how this could have been implemented. For a certain function handle (and by this I mean a <em>vpiHandle</em>) obtained from within an object we could set the contents of its <strong>input</strong> and <strong>inout</strong> arguments to our desired values via calls to <em>vpi_set_value(…)</em>. Afterwards, we could trigger a call of the function via some VPI function call. An idea would be to simply do a <em>vpi_put_value(…)</em> on the function handle itself. This would be consistent with how VPI code can trigger named events. After the call, we could get the returned value using <em>vpi_get_value(…)</em>.</p>

<p>Tasks are more complicated, though, because they can consume simulation time. We would be able to start a task from within an <em>invoke(…)</em> function and have it run in the background. Parallel behavior is modeled by threads and when starting a task, we’d need to specify where it gets started. Do we start a new thread, totally independent of all others? Do we start the task as a child process of the current thread? Regardless of where we would start the task, this could also be done by calling <em>vpi_put_value(…)</em> on the task handle. To be able to wait for a task to finish, we’d need to be able to set a callback for when its execution is completed. This callback could trigger an event which we would use for synchronization.</p>

<p>Implementing method calls via the VPI sounds like a lot of work, especially when handling tasks. It’s a shame that the <em>SystemVerilog</em> committee decided to skip it entirely. Maybe we’ll be lucky and it will make its way into the next IEEE 1800 release.</p>

<p>With this post I’m going to conclude our reflection series, but not before talking about some future steps. The first and most obvious is to test the library with a wider variety of simulators. I’d appreciate any help from enthusiastic users that have access to tools from other vendors. Another thing I’d like to implement is a more generic way of handling data types (i.e. an <em>rf_type</em> class), to be able to deal with both primitive and user defined types. This should make it easier to implement setting and getting of more than just <strong>int</strong> variables. A pretty cool thing would also be to be able to traverse the inheritance tree of a class, by getting its super-class and its sub-classes.</p>

<p>While the library is far from being usable in a production environment, you can get it from <a href="https://github.com/tudortimi/reflection">GitHub</a> and play around with it. If you do want to use it for something and it’s missing a feature you need, you can either open an issue or, even better, fork the repository, implement it yourself and send it upstream to be integrated.</p>]]></content><author><name>Tudor Timi</name></author><category term="Software development" /><category term="SystemVerilog" /><summary type="html"><![CDATA[We’ve already looked at how to interrogate classes about what variables they have and how to set and get the values of these variables in different instances. Classes are much more than just data containers, though. They also contain methods that can operate on their variables. In this post we’ll look at how we can handle tasks and functions inside our reflection API.]]></summary></entry><entry><title type="html">The Humble Beginnings of a SystemVerilog Reflection API, Part 2</title><link href="https://blog.verificationgentleman.com/2016/05/20/systemverilog-reflection-api-part2.html" rel="alternate" type="text/html" title="The Humble Beginnings of a SystemVerilog Reflection API, Part 2" /><published>2016-05-20T22:03:00+02:00</published><updated>2016-05-20T22:03:00+02:00</updated><id>https://blog.verificationgentleman.com/2016/05/20/systemverilog-reflection-api-part2</id><content type="html" xml:base="https://blog.verificationgentleman.com/2016/05/20/systemverilog-reflection-api-part2.html"><![CDATA[<p>In the <a href="/2016/04/10/systemverilog-reflection-api.html">previous post</a> we saw that it’s possible to use the Verilog Programming Interface (VPI) to programmatically get information about classes. For example, we can “ask” a class what variables it has. We’ve wrapped the calls to the <em>C</em> interface in a nice <em>SystemVerilog</em> library by using the Direct Programming Interface (DPI). While being able to mine the code for information about its structure can prove very useful, what this gives use is merely introspection. True reflection requires that we’re able to manipulate values stored inside objects, by getting or setting them.</p>

<p>As a template on how this part of the API should look, we’re going to take a peek at how <em>Java</em> handles reflection. The first thing to note is that in <em>Java</em> everything is a class (kind of). All classes extend the <em>Object</em> class implicitly. Even primitive types, such as <strong>int</strong> and <strong>char</strong>, are wrapped in classes (i.e. <em>Int</em> and <em>Char</em>, respectively). The primitive types and their class wrappers are also pretty much interchangeable via the mechanisms of <a href="https://docs.oracle.com/javase/tutorial/java/data/autoboxing.html">autoboxing and unboxing</a>.</p>

<p>The <a href="https://docs.oracle.com/javase/8/docs/api/java/lang/reflect/Field.html"><em>java.lang.reflect.Field</em></a> class (the counterpart to our <em>rf_variable</em> class) contains a <em>set(…)</em> method that allows it to change the value of the respective field for a given object instance. Since everything is an <em>Object</em>, the signature for this method is:</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">class</span> <span class="nc">Field</span> <span class="o">{</span>
  <span class="kd">public</span> <span class="kt">void</span> <span class="nf">set</span><span class="o">(</span><span class="nc">Object</span> <span class="n">obj</span><span class="o">,</span> <span class="nc">Object</span> <span class="n">value</span><span class="o">)</span> <span class="o">{</span>
    <span class="c1">// ...</span>
  <span class="o">}</span>

  <span class="c1">// ...</span>
<span class="o">}</span>
</code></pre></div></div>

<p>Things aren’t as easy in <em>SystemVerilog</em>. There isn’t any root class from which all other classes branch out. There’s also a clear separation between primitive types and classes. We’re going to have to find a way to get around this.</p>

<p>Let’s first look at what we can do about the <em>obj</em> argument of the aforementioned function. Since we don’t have a built-in <em>Object</em> class, we’re going to have to define our own. Our <em>set(…)</em> function will accept an instance of a class called <em>rf_object_instance_base</em>. This class will store a handle to the object as it is returned by the VPI (more details on this in a bit). We need to (somehow) pass references to objects of different types down to the VPI layer. These objects don’t have any lowest common denominator, in the form of a common base class.</p>

<p>We have a similar problem with the <em>value</em> argument. Our <em>set(…)</em> function could take an object of a container class, <em>rf_value_base</em>, which stores the value in an “abstract” way. The problem here is compounded by the fact that values can be any <em>SystemVerilog</em> type, built-in or user defined.</p>

<p>Based on the discussion above, we can enhance the <em>rf_variable</em> class to contain the following function:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">class</span> <span class="n">rf_variable</span><span class="p">;</span>
  <span class="k">function</span> <span class="kt">void</span> <span class="n">set</span><span class="p">(</span><span class="n">rf_object_instance_base</span> <span class="n">object</span><span class="p">,</span> <span class="n">rf_value_base</span> <span class="n">value</span><span class="p">);</span>

  <span class="c1">// ...</span>
<span class="k">endclass</span>
</code></pre></div></div>

<p>Now it’s time to take this fuzzy idea and put it into practice. Let’s start with the container for object instances. To be able to manipulate an object via the VPI, we need to know how to access it via a <em>vpiHandle</em>. The type of the object isn’t really that important. The <em>rf_object_instance_base</em> class only needs to store this handle:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">virtual</span> <span class="kt">class</span> <span class="n">rf_object_instance_base</span><span class="p">;</span>
  <span class="k">protected</span> <span class="n">vpiHandle</span> <span class="n">class_obj</span><span class="p">;</span>

  <span class="k">function</span> <span class="n">vpiHandle</span> <span class="n">get_class_obj</span><span class="p">();</span>
    <span class="k">return</span> <span class="n">class_obj</span><span class="p">;</span>
  <span class="k">endfunction</span>
<span class="k">endclass</span>
</code></pre></div></div>

<p>The difficult part is being able to get this handle from objects of different types. To do this without violating the language syntax we’ll have to use a parameterized class, <em>rf_object_instance #(…)</em>, which takes the object type as a parameter. This parameterized class only exists to make the compiler happy. It traverses the VPI model to find the <em>vpiHandle</em> of the object passed to its <em>get(…)</em> function:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">class</span> <span class="n">rf_object_instance</span> <span class="p">#(</span><span class="k">type</span> <span class="n">T</span> <span class="o">=</span> <span class="kt">int</span><span class="p">)</span> <span class="k">extends</span> <span class="n">rf_object_instance_base</span><span class="p">;</span>
  <span class="kt">static</span> <span class="k">function</span> <span class="n">rf_object_instance</span> <span class="p">#(</span><span class="n">T</span><span class="p">)</span> <span class="n">get</span><span class="p">(</span><span class="n">T</span> <span class="n">object</span><span class="p">);</span>
    <span class="n">vpiHandle</span> <span class="n">obj</span><span class="p">;</span>
    <span class="c1">// set 'obj' using the VPI</span>
    <span class="n">get</span> <span class="o">=</span> <span class="k">new</span><span class="p">(</span><span class="n">obj</span><span class="p">);</span>
    <span class="k">return</span> <span class="n">get</span><span class="p">;</span>
  <span class="k">endfunction</span>

  <span class="k">protected</span> <span class="k">function</span> <span class="k">new</span><span class="p">(</span><span class="n">vpiHandle</span> <span class="n">class_obj</span><span class="p">);</span>
    <span class="k">this</span><span class="p">.</span><span class="n">class_obj</span> <span class="o">=</span> <span class="n">class_obj</span><span class="p">;</span>
  <span class="k">endfunction</span>
<span class="k">endclass</span>
</code></pre></div></div>

<p>The exact steps required to do the traversal aren’t important for this discussion. One very important thing I learned after quite a bit of digging is that it’s very very very important to make sure that any simulator optimizations get turned off when trying to work with objects. Normally, for signals and variables the simulator will tell you when you’re trying to perform an illegal operation (such as reading a signal that doesn’t have read access). When trying to traverse class object relationships, you might not get any such messages. The exact symptom I was seeing was that I was getting a null <em>vpiHandle</em> for an existing object. I’ve added some sanity checks inside the traversal code to check for this situation, but there may be more pitfalls that I haven’t covered.</p>

<p>Here’s an example how we can get the instance container for an object:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">rf_object_instance_base</span> <span class="n">o</span> <span class="o">=</span> <span class="n">rf_object_instance</span> <span class="p">#(</span><span class="n">some_class</span><span class="p">)</span><span class="o">::</span><span class="n">get</span><span class="p">(</span><span class="n">some_obj</span><span class="p">);</span>
</code></pre></div></div>

<p>We can implement the same pattern to deal with values. As before, we need a base class. In this case, this base class doesn’t need to do anything, except sit there and look pretty for the compiler:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">virtual</span> <span class="kt">class</span> <span class="n">rf_value_base</span><span class="p">;</span>
<span class="k">endclass</span>
</code></pre></div></div>

<p>When we want to manipulate a concrete value, we can use a parameterized class, <em>rf_value #(…)</em>. For those of you familiar with <em>e</em>’s reflection capabilities, this concept is similar to using the <em>rf_value_holder</em> <strong>struct</strong>, together with the <strong>unsafe()</strong> operator. The parameterized class is going to do the heavy lifting:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">class</span> <span class="n">rf_value</span> <span class="p">#(</span><span class="k">type</span> <span class="n">T</span> <span class="o">=</span> <span class="kt">int</span><span class="p">)</span> <span class="k">extends</span> <span class="n">rf_value_base</span><span class="p">;</span>
  <span class="k">local</span> <span class="n">T</span> <span class="n">value</span><span class="p">;</span>
  <span class="k">local</span> <span class="kt">static</span> <span class="n">T</span> <span class="n">def_value</span><span class="p">;</span>

  <span class="k">function</span> <span class="k">new</span><span class="p">(</span><span class="n">T</span> <span class="n">value</span> <span class="o">=</span> <span class="n">def_value</span><span class="p">);</span>
    <span class="k">this</span><span class="p">.</span><span class="n">value</span> <span class="o">=</span> <span class="n">value</span><span class="p">;</span>
  <span class="k">endfunction</span>

  <span class="k">function</span> <span class="n">T</span> <span class="n">get</span><span class="p">();</span>
    <span class="k">return</span> <span class="n">value</span><span class="p">;</span>
  <span class="k">endfunction</span>

  <span class="k">function</span> <span class="kt">void</span> <span class="n">set</span><span class="p">(</span><span class="n">T</span> <span class="n">value</span><span class="p">);</span>
    <span class="k">this</span><span class="p">.</span><span class="n">value</span> <span class="o">=</span> <span class="n">value</span><span class="p">;</span>
  <span class="k">endfunction</span>
<span class="k">endclass</span>
</code></pre></div></div>

<p>The value stored in it can be set using the constructor:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">rf_value</span> <span class="p">#(</span><span class="kt">int</span><span class="p">)</span> <span class="n">v</span> <span class="o">=</span> <span class="k">new</span><span class="p">(</span><span class="mi">5</span><span class="p">);</span>
</code></pre></div></div>

<p>Notice, though, that the <em>get(…)</em> and <em>set(…)</em> functions only exist in the parameterized class. This means that the <em>rf_variable</em> class, which is going to use the value passed to it, needs to cast the container to it’s appropriate type.</p>

<p>Before we dive into the implementation of <em>rf_variable::set(…)</em>, we need a bit of background information. Getting and setting values is handled in a different way by the VPI than getting handles to simulation objects. Without turning this post into a VPI tutorial, let’s have a quick look at how this is done. There are two functions: <em>vpi_get_value(…)</em> and <em>vpi_put_value(…)</em>. The prototype for <em>vpi_get_value(…)</em> is:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">vpi_get_value</span><span class="p">(</span><span class="n">vpiHandle</span> <span class="n">obj</span><span class="p">,</span> <span class="n">p_vpi_value</span> <span class="n">value_p</span><span class="p">);</span>
</code></pre></div></div>

<p>The <em>obj</em> argument is a handle to the simulation object (signal or variable) that’s being interrogated and <em>p</em> is a pointer to a structure in which to store the value information. The type definition for this <em>p_vpi_value</em> <strong>struct</strong> is:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">typedef</span> <span class="k">struct</span> <span class="n">t_vpi_value</span> <span class="p">{</span>
  <span class="n">PLI_INT32</span> <span class="n">format</span><span class="p">;</span>
  <span class="k">union</span> <span class="p">{</span>
    <span class="n">PLI_BYTE8</span> <span class="o">*</span><span class="n">str</span><span class="p">;</span>
    <span class="n">PLI_INT32</span> <span class="n">scalar</span><span class="p">;</span>
    <span class="n">PLI_INT32</span> <span class="n">integer</span><span class="p">;</span>
    <span class="kt">double</span> <span class="n">real</span><span class="p">;</span>
    <span class="k">struct</span> <span class="n">t_vpi_time</span> <span class="o">*</span><span class="n">time</span><span class="p">;</span>
    <span class="k">struct</span> <span class="n">t_vpi_vecval</span> <span class="o">*</span><span class="n">vector</span><span class="p">;</span>
    <span class="k">struct</span> <span class="n">t_vpi_strengthval</span> <span class="o">*</span><span class="n">strength</span><span class="p">;</span>
    <span class="n">PLI_BYTE8</span> <span class="o">*</span><span class="n">misc</span><span class="p">;</span>
  <span class="p">}</span> <span class="n">value</span><span class="p">;</span>
<span class="p">}</span> <span class="n">s_vpi_value</span><span class="p">,</span> <span class="o">*</span><span class="n">p_vpi_value</span><span class="p">;</span>
</code></pre></div></div>

<p>This data type allows all kinds of values to be described. The exact contents of this structure and how they’re supposed to be used aren’t important. What is important to note is that passing this information across the language boundary (between <em>C</em> and <em>SystemVerilog</em>) isn’t going to be easy. First of all, this <em>C</em> structure just can’t be translated into an equivalent <em>SystemVerilog</em> representation, because the latter doesn’t have any concept of pointers. Secondly, even if we didn’t have the problem with pointers, most simulators are only going to support primitive types in DPI declarations (even though the standard allows for more complicated aggregate types).</p>

<p>Since we can’t work with any kind of value in a generic fashion, we’re going to have the break the problem down. If we can’t import the <em>vpi_get_value(…)</em> function directly, we can at least import a stripped down version of it that can only get integer values:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="nf">vpi_get_value_int</span><span class="p">(</span><span class="n">vpiHandle</span> <span class="n">obj</span><span class="p">)</span> <span class="p">{</span>
  <span class="n">s_vpi_value</span> <span class="n">v</span><span class="p">;</span>
  <span class="n">v</span><span class="p">.</span><span class="n">format</span> <span class="o">=</span> <span class="n">vpiIntVal</span><span class="p">;</span>
  <span class="n">vpi_get_value</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">v</span><span class="p">);</span>
  <span class="k">return</span> <span class="n">v</span><span class="p">.</span><span class="n">value</span><span class="p">.</span><span class="n">integer</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>We can do the same for its <em>set(…)</em> counterpart:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">vpi_put_value_int</span><span class="p">(</span><span class="n">vpiHandle</span> <span class="n">obj</span><span class="p">,</span> <span class="kt">int</span> <span class="n">value</span><span class="p">)</span> <span class="p">{</span>
  <span class="n">s_vpi_value</span> <span class="n">v</span><span class="p">;</span>
  <span class="n">v</span><span class="p">.</span><span class="n">format</span> <span class="o">=</span> <span class="n">vpiIntVal</span><span class="p">;</span>
  <span class="n">v</span><span class="p">.</span><span class="n">value</span><span class="p">.</span><span class="n">integer</span> <span class="o">=</span> <span class="n">value</span><span class="p">;</span>
  <span class="n">vpi_put_value</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">v</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="n">vpiNoDelay</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Since these functions only use primitive types for their arguments and return values, we can import them using the DPI:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">import</span> <span class="s">"DPI-C"</span> <span class="k">context</span>
  <span class="k">function</span> <span class="kt">int</span> <span class="n">vpi_get_value_int</span><span class="p">(</span><span class="n">vpiHandle</span> <span class="n">obj</span><span class="p">);</span>

<span class="k">import</span> <span class="s">"DPI-C"</span> <span class="k">context</span>
  <span class="k">function</span> <span class="kt">void</span> <span class="n">vpi_put_value_int</span><span class="p">(</span><span class="n">vpiHandle</span> <span class="n">obj</span><span class="p">,</span> <span class="kt">int</span> <span class="n">value</span><span class="p">);</span>
</code></pre></div></div>

<p>After this long detour, let’s get back to the task at hand. Because we’ll have multiple variants of the <em>get_*(…)</em> and <em>put_*(…)</em> functions in the VPI layer, the <em>rf_variable</em> class needs to know which one of them to call, based on the type of variable we’re operating on. Since we can only operate on integers at the moment, let’s limit the discussion to this type.</p>

<p>The only way I can currently envision implementing this is by writing a big <strong>case</strong> statement, which dispatches different functions depending on the variable’s type:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">function</span> <span class="kt">void</span> <span class="n">rf_variable</span><span class="o">::</span><span class="n">set</span><span class="p">(</span><span class="n">rf_object_instance_base</span> <span class="n">object</span><span class="p">,</span> <span class="n">rf_value_base</span> <span class="n">value</span><span class="p">);</span>
  <span class="n">vpiHandle</span> <span class="n">var_</span> <span class="o">=</span> <span class="n">get_var</span><span class="p">(</span><span class="n">object</span><span class="p">);</span>
  <span class="k">case</span> <span class="p">(</span><span class="n">vpi_get_str</span><span class="p">(</span><span class="n">vpiType</span><span class="p">,</span> <span class="n">var_</span><span class="p">))</span>
    <span class="s">"vpiIntVar"</span> <span class="o">:</span> <span class="n">set_value_int</span><span class="p">(</span><span class="n">var_</span><span class="p">,</span> <span class="n">value</span><span class="p">);</span>
    <span class="k">default</span> <span class="o">:</span> <span class="p">$</span><span class="n">fatal</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="s">"Type '%s' not implemented"</span><span class="p">,</span> <span class="n">vpi_get_str</span><span class="p">(</span><span class="n">vpiType</span><span class="p">,</span>
      <span class="n">var_</span><span class="p">));</span>
  <span class="k">endcase</span>
<span class="k">endfunction</span>
</code></pre></div></div>

<p>The <strong>case</strong> is quite boring now, but you get the idea. We’d add a new item of each type we want to support. User defined types are for sure going to be a blast to implement…</p>

<p>The <em>get_var(…)</em> function traverses the VPI model to get the handle for the chosen variable inside the given object instance. It’s implementation isn’t that important for this discussion. More interesting is the <em>set_value_int(…)</em> function:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">class</span> <span class="n">rf_variable</span><span class="p">;</span>
  <span class="k">local</span> <span class="k">function</span> <span class="kt">void</span> <span class="n">set_value_int</span><span class="p">(</span><span class="n">vpiHandle</span> <span class="n">var_</span><span class="p">,</span> <span class="n">rf_value_base</span> <span class="n">value</span><span class="p">);</span>
    <span class="n">rf_value</span> <span class="p">#(</span><span class="kt">int</span><span class="p">)</span> <span class="n">val</span><span class="p">;</span>
    <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="p">$</span><span class="nb">cast</span><span class="p">(</span><span class="n">val</span><span class="p">,</span> <span class="n">value</span><span class="p">))</span>
      <span class="p">$</span><span class="n">fatal</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="s">"Internal error"</span><span class="p">);</span>
    <span class="n">vpi_put_value_int</span><span class="p">(</span><span class="n">var_</span><span class="p">,</span> <span class="n">val</span><span class="p">.</span><span class="n">get</span><span class="p">());</span>
  <span class="k">endfunction</span>

  <span class="c1">// ...</span>
<span class="k">endclass</span>
</code></pre></div></div>

<p>As we saw above, to be able to access the value stored in the container, we need to cast it to its parameterization. Afterwards we can get use this value as an argument to <em>vpi_put_value(…)</em>.</p>

<p>Getting the value of an object’s variable can be done in the same way:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">function</span> <span class="n">rf_value_base</span> <span class="n">rf_variable</span><span class="o">::</span><span class="n">get</span><span class="p">(</span><span class="n">rf_object_instance_base</span> <span class="n">object</span><span class="p">);</span>
  <span class="n">vpiHandle</span> <span class="n">var_</span> <span class="o">=</span> <span class="n">get_var</span><span class="p">(</span><span class="n">object</span><span class="p">);</span>
  <span class="k">case</span> <span class="p">(</span><span class="n">vpi_get_str</span><span class="p">(</span><span class="n">vpiType</span><span class="p">,</span> <span class="n">var_</span><span class="p">))</span>
    <span class="s">"vpiIntVar"</span> <span class="o">:</span> <span class="k">return</span> <span class="n">get_value_int</span><span class="p">(</span><span class="n">var_</span><span class="p">);</span>
    <span class="k">default</span> <span class="o">:</span> <span class="p">$</span><span class="n">fatal</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="s">"Type '%s' not implemented"</span><span class="p">,</span> <span class="n">vpi_get_str</span><span class="p">(</span><span class="n">vpiType</span><span class="p">,</span>
      <span class="n">var_</span><span class="p">));</span>
  <span class="k">endcase</span>
<span class="k">endfunction</span>
</code></pre></div></div>

<p>Here, the <em>get_value_int(…)</em> gets the value via the VPI:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">class</span> <span class="n">rf_variable</span><span class="p">;</span>
  <span class="k">local</span> <span class="k">function</span> <span class="n">rf_value_base</span> <span class="n">get_value_int</span><span class="p">(</span><span class="n">vpiHandle</span> <span class="n">var_</span><span class="p">);</span>
    <span class="n">rf_value</span> <span class="p">#(</span><span class="kt">int</span><span class="p">)</span> <span class="n">ret</span> <span class="o">=</span> <span class="k">new</span><span class="p">();</span>
    <span class="n">ret</span><span class="p">.</span><span class="n">set</span><span class="p">(</span><span class="n">vpi_get_value_int</span><span class="p">(</span><span class="n">var_</span><span class="p">));</span>
    <span class="k">return</span> <span class="n">ret</span><span class="p">;</span>
  <span class="k">endfunction</span>

  <span class="c1">// ...</span>
<span class="k">endclass</span>
</code></pre></div></div>

<p>Using these two functions, it’s possible to manipulate and interrogate the values of class variables using reflection:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">rf_value</span> <span class="p">#(</span><span class="kt">int</span><span class="p">)</span> <span class="n">v</span> <span class="o">=</span> <span class="k">new</span><span class="p">(</span><span class="mi">5</span><span class="p">);</span>
<span class="n">some_var</span><span class="p">.</span><span class="n">set</span><span class="p">(</span><span class="n">rf_object_instance</span> <span class="p">#(</span><span class="n">some_class</span><span class="p">)</span><span class="o">::</span><span class="n">get</span><span class="p">(</span><span class="n">some_obj</span><span class="p">),</span> <span class="n">v</span><span class="p">);</span>
<span class="kt">void</span><span class="err">'</span><span class="p">(</span><span class="o">!</span><span class="p">$</span><span class="nb">cast</span><span class="p">(</span><span class="n">v</span><span class="p">,</span> <span class="n">some_var</span><span class="p">.</span><span class="n">set</span><span class="p">(</span><span class="n">rf_object_instance</span> <span class="p">#(</span><span class="n">some_class</span><span class="p">)</span><span class="o">::</span><span class="n">get</span><span class="p">(</span><span class="n">some_obj</span><span class="p">))));</span>
</code></pre></div></div>

<p>I’m not particularly thrilled by having to implement a new pair of <em>get_value_</em>(…)/<em>set_value_</em>(…)* functions for each new type that we want to support, but at least this is an internal implementation detail that doesn’t affect the API. It can always be changed if something better comes along. Using a <strong>case</strong> statement and casting are also frowned upon in the OOP community, because they can usually be avoided by using polymorphism. If anyone has a cleaner implementation, this is also something that can be changed without making any modifications to the API.</p>

<p>If you want to give it a go for yourself, you can download the library from <a href="https://github.com/tudortimi/reflection">GitHub</a>. At this point in time, the value getting/setting API is in the proof of concept stage. I’ll add new types on request. If you don’t want to wait for me you can get your hands dirty and contribute!</p>]]></content><author><name>Tudor Timi</name></author><category term="Software development" /><category term="SystemVerilog" /><summary type="html"><![CDATA[In the previous post we saw that it’s possible to use the Verilog Programming Interface (VPI) to programmatically get information about classes. For example, we can “ask” a class what variables it has. We’ve wrapped the calls to the C interface in a nice SystemVerilog library by using the Direct Programming Interface (DPI). While being able to mine the code for information about its structure can prove very useful, what this gives use is merely introspection. True reflection requires that we’re able to manipulate values stored inside objects, by getting or setting them.]]></summary></entry><entry><title type="html">The Humble Beginnings of a SystemVerilog Reflection API</title><link href="https://blog.verificationgentleman.com/2016/04/10/systemverilog-reflection-api.html" rel="alternate" type="text/html" title="The Humble Beginnings of a SystemVerilog Reflection API" /><published>2016-04-10T18:34:00+02:00</published><updated>2016-04-10T18:34:00+02:00</updated><id>https://blog.verificationgentleman.com/2016/04/10/systemverilog-reflection-api</id><content type="html" xml:base="https://blog.verificationgentleman.com/2016/04/10/systemverilog-reflection-api.html"><![CDATA[<p><a href="https://en.wikipedia.org/wiki/Reflection_%28computer_programming%29">Reflection</a> is a mechanism that allows “inspection of classes, interfaces, fields and methods at runtime without knowing the names of the interfaces, fields, methods at compile time. It also allows instantiation of new objects and invocation of methods”. In <em>e</em>, using reflection together with <strong>define as computed</strong> macros allows us to do some really cool stuff.</p>

<p>A major complaint about <em>SystemVerilog</em> is that it lacks reflection capabilities. These could be useful for writing super generic code, but the main use I can see, though, is in testing. For example, in <em>Java</em>, the JUnit framework decides which methods to execute as unit tests based on annotations (<em>@Test</em>). Reflection could also allow a user to write some very generic checks, for example checking that after a method call the <code class="language-plaintext highlighter-rouge">rand_mode()</code> attribute of all variables of an object is set to 0. Mocking frameworks also use a lot of reflection to do their thing (I hear), though I don’t really know the exact details.</p>

<p><em>Verilog</em> and <em>SystemVerilog</em> provide the <em>Verilog Programming Interface</em> (VPI), which the IEEE 1800-2012 standard describes as a part of the “procedural interface that allows foreign language functions to access the internal data structures of a SystemVerilog simulation”. It is defined as a <em>C</em> programming language interface to be used for writing <em>C</em> applications. Unfortunately, these functions aren’t directly available in a <em>SystemVerilog</em> package. I’ve no idea why, since this is pretty low hanging fruit. (This isn’t 100% true, since it is possible to use the VPI to “enhance” the simulator by defining new system tasks and functions, but the process is very cumbersome.)</p>

<p>I’ve used the VPI for some past projects. It’s written in an object oriented style, but since it’s plain old <em>C</em> code it doesn’t have the same feel as a proper OOP language. This makes it not quite so comfortable to use. It is pretty powerful, though, and it allows a developer to mine a lot of information out of the compiled <em>SystemVerilog</em> code. On the other side of the HVL barricade, <em>e</em>’s reflection API is excellent. It’s every bit as powerful and very comfortable to use, making it a worthy reference.</p>

<p>Our goal in this post is to define a reflection API for <em>SystemVerilog</em>. Anything we develop should have a nice object oriented interface, with classes to model each language construct (i.e. variables, functions, tasks, classes, etc.). The most reasonable (and only) course of action is to leverage the existing VPI, by building an adaption layer.</p>

<p>The first thing we need to do is to find a way to access the VPI routines which are available in <em>C</em> from code written in <em>SystemVerilog</em>. Fortunately, this is possible via the <em>Direct Programming Interface</em> (DPI), which allows us to call code written in other programming languages. The interface to <em>C</em> code (called DPI-C) is thoroughly defined in the standard. We can use it write a package that imports the VPI functions into <em>SystemVerilog</em>. Apparently Dave Rich already beat me to the punch here (by a couple of years judging from the code comments), with his DVCon 2016 paper, <em>Introspection into SystemVerilog without Turning It Inside Out</em>, where he presents this exact idea. I had already created my own repository on GitHub, <a href="https://github.com/tudortimi/vpi">vpi</a>, before reading his paper, so we’ll be using that.</p>

<p>The VPI is fully documented in Annexes K, L and M of the IEEE 1800-2012 standard. These sections contain the header files that simulators must provide for VPI applications to include. In this post we’re mostly interested in the parts related to classes and variables. For the next sections, I’ll assume that readers are already familiar with the VPI. If you’re new to the topic, you should give Sections 36, 37 (especially) and 38 of the LRM a quick read before you continue.</p>

<p>The first step is to mirror the type definitions on the <em>C</em> side into <em>SystemVerilog</em>. The DPI-C allows defines a rich set of equivalent type mappings from one language to the other, so this step is pretty straightforward:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">typedef</span> <span class="kt">int</span> <span class="n">PLI_INT32</span><span class="p">;</span>
<span class="k">typedef</span> <span class="kt">longint</span> <span class="n">PLI_INT64</span><span class="p">;</span>
<span class="k">typedef</span> <span class="kt">chandle</span> <span class="n">vpiHandle</span><span class="p">;</span>
</code></pre></div></div>

<p>The basic thing we can do with a <code class="language-plaintext highlighter-rouge">vpiHandle</code> is to get certain properties it has. The properties simulation objects can have are defined in the VPI headers and also need to be mirrored into <em>SystemVerilog</em>:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">parameter</span> <span class="n">vpiUndefined</span> <span class="o">=</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span>
<span class="k">parameter</span> <span class="n">vpiType</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
<span class="k">parameter</span> <span class="n">vpiName</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>

<span class="k">parameter</span> <span class="n">vpiRandType</span> <span class="o">=</span> <span class="mi">610</span><span class="p">;</span>
<span class="k">parameter</span> <span class="n">vpiNotRand</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
<span class="k">parameter</span> <span class="n">vpiRand</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
<span class="k">parameter</span> <span class="n">vpiRandC</span> <span class="o">=</span> <span class="mi">3</span><span class="p">;</span>
</code></pre></div></div>

<p>I’ve used parameters inside the package for them, but they could just as well have been constants. I’m not really sure what would have been better here (though now on second glance I’m leaning toward constants), so if you have some input here, I’d love to hear it.</p>

<p>Simulation objects are typically “connected” to each other via references. To traverse one-to-one relationships (e.g. a class has a class definition), we need to define the corresponding object types:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">parameter</span> <span class="n">vpiModule</span> <span class="o">=</span> <span class="mi">32</span><span class="p">;</span>
<span class="k">parameter</span> <span class="n">vpiPackage</span> <span class="o">=</span> <span class="mi">600</span><span class="p">;</span>
<span class="k">parameter</span> <span class="n">vpiClassDefn</span> <span class="o">=</span> <span class="mi">652</span><span class="p">;</span>
</code></pre></div></div>

<p>It can also be the case that one simulation objects contains references to multiple other simulation objects of the same type (e.g. a class definition contains multiple variables). For traversing one-to-many relationships we need to define the appropriate values to pass to <code class="language-plaintext highlighter-rouge">vpi_iterate(...)</code>:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">parameter</span> <span class="n">vpiVariables</span> <span class="o">=</span> <span class="mi">100</span><span class="p">;</span>
</code></pre></div></div>

<p>Once we’ve set up our types and our other constants, we can import the VPI functions using the DPI-C:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">import</span> <span class="s">"DPI-C"</span> <span class="k">context</span>
  <span class="k">function</span> <span class="n">PLI_INT32</span> <span class="n">vpi_get</span><span class="p">(</span><span class="n">PLI_INT32</span> <span class="n">prop</span><span class="p">,</span> <span class="n">vpiHandle</span> <span class="n">obj</span><span class="p">);</span>

<span class="k">import</span> <span class="s">"DPI-C"</span> <span class="k">context</span>
  <span class="k">function</span> <span class="n">PLI_INT64</span> <span class="n">vpi_get64</span><span class="p">(</span><span class="n">PLI_INT32</span> <span class="n">prop</span><span class="p">,</span> <span class="n">vpiHandle</span> <span class="n">obj</span><span class="p">);</span>

<span class="k">import</span> <span class="s">"DPI-C"</span> <span class="k">context</span>
  <span class="k">function</span> <span class="kt">string</span> <span class="n">vpi_get_str</span><span class="p">(</span><span class="n">PLI_INT32</span> <span class="n">prop</span><span class="p">,</span> <span class="n">vpiHandle</span> <span class="n">obj</span><span class="p">);</span>

<span class="k">import</span> <span class="s">"DPI-C"</span> <span class="k">context</span>
  <span class="k">function</span> <span class="n">vpiHandle</span> <span class="n">vpi_iterate</span><span class="p">(</span><span class="n">PLI_INT32</span> <span class="n">type_</span><span class="p">,</span> <span class="n">vpiHandle</span> <span class="n">ref_</span><span class="p">);</span>

<span class="k">import</span> <span class="s">"DPI-C"</span> <span class="k">context</span>
  <span class="k">function</span> <span class="n">vpiHandle</span> <span class="n">vpi_handle</span><span class="p">(</span><span class="n">PLI_INT32</span> <span class="n">type_</span><span class="p">,</span> <span class="n">vpiHandle</span> <span class="n">ref_</span><span class="p">);</span>

<span class="k">import</span> <span class="s">"DPI-C"</span> <span class="k">context</span>
  <span class="k">function</span> <span class="n">vpiHandle</span> <span class="n">vpi_scan</span><span class="p">(</span><span class="n">vpiHandle</span> <span class="n">itr</span><span class="p">);</span>
</code></pre></div></div>

<p>I’ve tried to use the same names for the arguments as in the LRM, but some of them are <em>SystemVerilog</em> keywords. In these cases I added an underscore as a suffix.</p>

<p>This didn’t work directly when trying to compile the code. The <em>SystemVerilog</em> compiler complained that it couldn’t find the <code class="language-plaintext highlighter-rouge">vpi_*(...)</code> functions anywhere. I guess this has something to do with the fact that when compiling it doesn’t link the VPI binaries. What I tried to do is to define a dummy <em>C</em> file that just includes the VPI header:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">"vpi_user.h"</span><span class="cp">
</span></code></pre></div></div>

<p>I hope that this way I could force the linking to happen. This didn’t really help. I think this is because, since we don’t use any of the functions declared in the header, the <em>C</em> compiler assumes that we don’t need them at all. After some searching online, I tried to find out if it’s possible to force the compiler/linker to link unused symbols. This is what my search pointed me to:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">PLI_BYTE8</span><span class="o">*</span> <span class="p">(</span><span class="o">*</span><span class="n">vpi_get_str__</span><span class="p">)(</span><span class="n">PLI_INT32</span><span class="p">,</span> <span class="n">vpiHandle</span><span class="p">)</span> <span class="o">=</span> <span class="o">&amp;</span><span class="n">vpi_get_str</span><span class="p">;</span>
</code></pre></div></div>

<p>I’m not a <em>C</em> expert, so don’t quote me on this, but I think the code above should declare a function pointer with the respective return and argument types called <code class="language-plaintext highlighter-rouge">vpi_get_str__(...)</code> that points to the original <code class="language-plaintext highlighter-rouge">vpi_get_str(...)</code> function. Then, in our import code, instead of importing <code class="language-plaintext highlighter-rouge">vpi_get_str(...)</code>, we would import <code class="language-plaintext highlighter-rouge">vpi_get_str__(...)</code>. This also didn’t work.</p>

<p>The only thing that did work was to define <code class="language-plaintext highlighter-rouge">vpi_get_str__(...)</code> as a wrapper function that calls the real <code class="language-plaintext highlighter-rouge">vpi_get_str(...)</code>:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">PLI_BYTE8</span><span class="o">*</span> <span class="nf">vpi_get_str__</span><span class="p">(</span><span class="n">PLI_INT32</span> <span class="n">prop</span><span class="p">,</span> <span class="n">vpiHandle</span> <span class="n">obj</span><span class="p">)</span> <span class="p">{</span>
  <span class="k">return</span> <span class="n">vpi_get_str</span><span class="p">(</span><span class="n">prop</span><span class="p">,</span> <span class="n">obj</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>After doing this for the other functions as well, I ended up with the following DPI-C imports:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">import</span> <span class="s">"DPI-C"</span> <span class="k">context</span> <span class="n">vpi_get__</span> <span class="o">=</span>
  <span class="k">function</span> <span class="n">PLI_INT32</span> <span class="n">vpi_get</span><span class="p">(</span><span class="n">PLI_INT32</span> <span class="n">prop</span><span class="p">,</span> <span class="n">vpiHandle</span> <span class="n">obj</span><span class="p">);</span>

<span class="k">import</span> <span class="s">"DPI-C"</span> <span class="k">context</span> <span class="n">vpi_get64__</span> <span class="o">=</span>
  <span class="k">function</span> <span class="n">PLI_INT64</span> <span class="n">vpi_get64</span><span class="p">(</span><span class="n">PLI_INT32</span> <span class="n">prop</span><span class="p">,</span> <span class="n">vpiHandle</span> <span class="n">obj</span><span class="p">);</span>

<span class="k">import</span> <span class="s">"DPI-C"</span> <span class="k">context</span> <span class="n">vpi_get_str__</span> <span class="o">=</span>
  <span class="k">function</span> <span class="kt">string</span> <span class="n">vpi_get_str</span><span class="p">(</span><span class="n">PLI_INT32</span> <span class="n">prop</span><span class="p">,</span> <span class="n">vpiHandle</span> <span class="n">obj</span><span class="p">);</span>

<span class="k">import</span> <span class="s">"DPI-C"</span> <span class="k">context</span> <span class="n">vpi_iterate__</span> <span class="o">=</span>
  <span class="k">function</span> <span class="n">vpiHandle</span> <span class="n">vpi_iterate</span><span class="p">(</span><span class="n">PLI_INT32</span> <span class="n">type_</span><span class="p">,</span> <span class="n">vpiHandle</span> <span class="n">ref_</span><span class="p">);</span>

<span class="k">import</span> <span class="s">"DPI-C"</span> <span class="k">context</span> <span class="k">function</span> <span class="n">vpiHandle</span> <span class="n">vpi_handle</span><span class="p">(</span><span class="n">PLI_INT32</span> <span class="n">type_</span><span class="p">,</span>
  <span class="n">vpiHandle</span> <span class="n">ref_</span><span class="p">);</span>

<span class="k">import</span> <span class="s">"DPI-C"</span> <span class="k">context</span> <span class="n">vpi_scan__</span> <span class="o">=</span>
  <span class="k">function</span> <span class="n">vpiHandle</span> <span class="n">vpi_scan</span><span class="p">(</span><span class="n">vpiHandle</span> <span class="n">itr</span><span class="p">);</span>
</code></pre></div></div>

<p>Instead of importing the original <code class="language-plaintext highlighter-rouge">vpi_*(...)</code> functions I imported the wrappers, which worked perfectly. I guess this is because the <em>C</em> compiler was happy when it saw the VPI functions getting used. While writing the post, though, I noticed that I didn’t do this for <code class="language-plaintext highlighter-rouge">vpi_handle(...)</code>, which I imported directly. This whole process of writing wrappers and importing them is pretty tedious, so if anyone has any idea what’s going on here and how the imports could be streamlined, I’d very much appreciate it.</p>

<p>Implementation aspects aside, it’s time to see the package in action:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">module</span> <span class="n">test</span><span class="p">;</span>
  <span class="k">import</span> <span class="n">vpi</span><span class="o">::*</span><span class="p">;</span>

  <span class="k">initial</span> <span class="k">begin</span>
    <span class="k">automatic</span> <span class="kt">chandle</span> <span class="n">mod_it</span> <span class="o">=</span> <span class="n">vpi_iterate</span><span class="p">(</span><span class="n">vpiModule</span><span class="p">,</span> <span class="k">null</span><span class="p">);</span>

    <span class="k">automatic</span> <span class="kt">chandle</span> <span class="n">root</span> <span class="o">=</span> <span class="n">vpi_scan</span><span class="p">(</span><span class="n">mod_it</span><span class="p">);</span>
    <span class="p">$</span><span class="nb">display</span><span class="p">(</span><span class="s">"root = %d"</span><span class="p">,</span> <span class="n">root</span><span class="p">);</span>
    <span class="p">$</span><span class="nb">display</span><span class="p">(</span><span class="s">"  type = %s"</span><span class="p">,</span> <span class="n">vpi_get_str</span><span class="p">(</span><span class="n">vpiType</span><span class="p">,</span> <span class="n">root</span><span class="p">));</span>
    <span class="p">$</span><span class="nb">display</span><span class="p">(</span><span class="s">"  name = %s"</span><span class="p">,</span> <span class="n">vpi_get_str</span><span class="p">(</span><span class="n">vpiName</span><span class="p">,</span> <span class="n">root</span><span class="p">));</span>

    <span class="k">if</span> <span class="p">(</span><span class="n">vpi_scan</span><span class="p">(</span><span class="n">mod_it</span><span class="p">)</span> <span class="o">==</span> <span class="k">null</span><span class="p">)</span>
      <span class="p">$</span><span class="nb">display</span><span class="p">(</span><span class="s">"no more top modules"</span><span class="p">);</span>
  <span class="k">end</span>
<span class="k">endmodule</span>
</code></pre></div></div>

<p>The code above is going to figure out that the root module is called <code class="language-plaintext highlighter-rouge">test</code> and tells us that there are no more root modules. This isn’t particularly impressive, but the important thing to note is that it’s written exclusively in <em>SystemVerilog</em>.</p>

<p>Now that we’ve got the power of the VPI at our fingertips, it’s time to start thinking about how to implement our reflection API. All reflection operations in <em>e</em> are handled by the <code class="language-plaintext highlighter-rouge">rf_manager</code> <strong>struct</strong>. This is as good a name as any other for the top level entity that I can think of at the moment. We want our <code class="language-plaintext highlighter-rouge">rf_manager</code> to be able to give us an object that contains all of the information about a certain class. This object will be of type <code class="language-plaintext highlighter-rouge">rf_class</code>. As a first step, we want to get the corresponding <code class="language-plaintext highlighter-rouge">rf_class</code> object based on the class name:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">class</span> <span class="n">rf_manager</span><span class="p">;</span>
  <span class="k">extern</span> <span class="kt">static</span> <span class="k">function</span> <span class="n">rf_class</span> <span class="n">get_class_by_name</span><span class="p">(</span><span class="kt">string</span> <span class="n">name</span><span class="p">);</span>
<span class="k">endclass</span>
</code></pre></div></div>

<p>The <code class="language-plaintext highlighter-rouge">get_class_by_name(...)</code> method needs to look into our compiled library and check if it can find the definition of a class with the supplied name. This is done by traversing the VPI object model:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">function</span> <span class="n">rf_class</span> <span class="n">rf_manager</span><span class="o">::</span><span class="n">get_class_by_name</span><span class="p">(</span><span class="kt">string</span> <span class="n">name</span><span class="p">);</span>
  <span class="n">vpiHandle</span> <span class="n">package_it</span> <span class="o">=</span> <span class="n">vpi_iterate</span><span class="p">(</span><span class="n">vpiPackage</span><span class="p">,</span> <span class="k">null</span><span class="p">);</span>

  <span class="k">while</span> <span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="k">begin</span>
    <span class="n">vpiHandle</span> <span class="n">package_</span> <span class="o">=</span> <span class="n">vpi_scan</span><span class="p">(</span><span class="n">package_it</span><span class="p">);</span>
    <span class="n">vpiHandle</span> <span class="n">classdefn_it</span><span class="p">;</span>

    <span class="k">if</span> <span class="p">(</span><span class="n">package_</span> <span class="o">==</span> <span class="k">null</span><span class="p">)</span>
      <span class="k">break</span><span class="p">;</span>
    <span class="n">classdefn_it</span> <span class="o">=</span> <span class="n">vpi_iterate</span><span class="p">(</span><span class="n">vpiClassDefn</span><span class="p">,</span> <span class="n">package_</span><span class="p">);</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">classdefn_it</span> <span class="o">==</span> <span class="k">null</span><span class="p">)</span>
      <span class="k">continue</span><span class="p">;</span>

    <span class="k">while</span> <span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="k">begin</span>
      <span class="n">vpiHandle</span> <span class="n">classdefn</span> <span class="o">=</span> <span class="n">vpi_scan</span><span class="p">(</span><span class="n">classdefn_it</span><span class="p">);</span>
      <span class="k">if</span> <span class="p">(</span><span class="n">classdefn</span> <span class="o">==</span> <span class="k">null</span><span class="p">)</span>
        <span class="k">break</span><span class="p">;</span>
      <span class="k">if</span> <span class="p">(</span><span class="n">vpi_get_str</span><span class="p">(</span><span class="n">vpiName</span><span class="p">,</span> <span class="n">classdefn</span><span class="p">)</span> <span class="o">==</span> <span class="n">name</span><span class="p">)</span> <span class="k">begin</span>
        <span class="n">rf_class</span> <span class="n">c</span> <span class="o">=</span> <span class="k">new</span><span class="p">(</span><span class="n">classdefn</span><span class="p">);</span>
        <span class="k">return</span> <span class="n">c</span><span class="p">;</span>
      <span class="k">end</span>
    <span class="k">end</span>
  <span class="k">end</span>
<span class="k">endfunction</span>
</code></pre></div></div>

<p>The code above has some limitations. It only works for classes defined in packages and if the class name is used in multiple packages, it’s going to stop at the first one it finds. This is something that’s going to get fixed later, but now we’re at the proof-of-concept phase.</p>

<p>I’ve made the <code class="language-plaintext highlighter-rouge">get_class_by_name(...)</code> static inside <code class="language-plaintext highlighter-rouge">rf_manager</code>, but a better idea might have been to make <code class="language-plaintext highlighter-rouge">rf_manager</code> a singleton and leave the function non-static. This way I could later implement state inside the class, which would be useful, for example, to cache calls to reflection methods (since I’m assuming VPI calls don’t come cheap). I’m curious what you’re thoughts are here.</p>

<p>What could we want to know about a class? For starters, we’d like to know its name and what variables are declared inside it:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">class</span> <span class="n">rf_class</span><span class="p">;</span>
  <span class="k">extern</span> <span class="k">function</span> <span class="kt">string</span> <span class="n">get_name</span><span class="p">();</span>
  <span class="k">extern</span> <span class="k">function</span> <span class="n">array_of_rf_variable</span> <span class="n">get_variables</span><span class="p">();</span>
  <span class="k">extern</span> <span class="k">function</span> <span class="n">rf_variable</span> <span class="n">get_variable_by_name</span><span class="p">(</span><span class="kt">string</span> <span class="n">name</span><span class="p">);</span>

  <span class="k">extern</span> <span class="k">function</span> <span class="k">new</span><span class="p">(</span><span class="n">vpiHandle</span> <span class="n">classDefn</span><span class="p">);</span>
<span class="k">endclass</span>
</code></pre></div></div>

<p>We can get all of this information by traversing the VPI object model of the class definition, which is defined in Section 37.29 of the LRM:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">function</span> <span class="kt">string</span> <span class="n">rf_class</span><span class="o">::</span><span class="n">get_name</span><span class="p">();</span>
  <span class="k">return</span> <span class="n">vpi_get_str</span><span class="p">(</span><span class="n">vpiName</span><span class="p">,</span> <span class="n">classDefn</span><span class="p">);</span>
<span class="k">endfunction</span>


<span class="k">function</span> <span class="n">array_of_rf_variable</span> <span class="n">rf_class</span><span class="o">::</span><span class="n">get_variables</span><span class="p">();</span>
  <span class="n">rf_variable</span> <span class="n">vars</span><span class="p">[$];</span>
  <span class="n">vpiHandle</span> <span class="n">variables_it</span> <span class="o">=</span> <span class="n">vpi_iterate</span><span class="p">(</span><span class="n">vpiVariables</span><span class="p">,</span> <span class="n">classDefn</span><span class="p">);</span>
  <span class="k">while</span> <span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="k">begin</span>
    <span class="n">rf_variable</span> <span class="n">v</span><span class="p">;</span>
    <span class="n">vpiHandle</span> <span class="n">variable</span> <span class="o">=</span> <span class="n">vpi_scan</span><span class="p">(</span><span class="n">variables_it</span><span class="p">);</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">variable</span> <span class="o">==</span> <span class="k">null</span><span class="p">)</span>
      <span class="k">break</span><span class="p">;</span>
    <span class="n">v</span> <span class="o">=</span> <span class="k">new</span><span class="p">(</span><span class="n">variable</span><span class="p">);</span>
    <span class="n">vars</span><span class="p">.</span><span class="n">push_back</span><span class="p">(</span><span class="n">v</span><span class="p">);</span>
  <span class="k">end</span>
  <span class="k">return</span> <span class="n">vars</span><span class="p">;</span>
<span class="k">endfunction</span>


<span class="k">function</span> <span class="n">rf_variable</span> <span class="n">rf_class</span><span class="o">::</span><span class="n">get_variable_by_name</span><span class="p">(</span><span class="kt">string</span> <span class="n">name</span><span class="p">);</span>
  <span class="n">vpiHandle</span> <span class="n">variables_it</span> <span class="o">=</span> <span class="n">vpi_iterate</span><span class="p">(</span><span class="n">vpiVariables</span><span class="p">,</span> <span class="n">classDefn</span><span class="p">);</span>
  <span class="k">while</span> <span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="k">begin</span>
    <span class="n">vpiHandle</span> <span class="n">variable</span> <span class="o">=</span> <span class="n">vpi_scan</span><span class="p">(</span><span class="n">variables_it</span><span class="p">);</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">variable</span> <span class="o">==</span> <span class="k">null</span><span class="p">)</span>
      <span class="k">break</span><span class="p">;</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">vpi_get_str</span><span class="p">(</span><span class="n">vpiName</span><span class="p">,</span> <span class="n">variable</span><span class="p">)</span> <span class="o">==</span> <span class="n">name</span><span class="p">)</span> <span class="k">begin</span>
      <span class="n">rf_variable</span> <span class="n">v</span> <span class="o">=</span> <span class="k">new</span><span class="p">(</span><span class="n">variable</span><span class="p">);</span>
      <span class="k">return</span> <span class="n">v</span><span class="p">;</span>
    <span class="k">end</span>
  <span class="k">end</span>
<span class="k">endfunction</span>
</code></pre></div></div>

<p>Once we have an object of type <code class="language-plaintext highlighter-rouge">rf_variable</code>, we can get its name or we can ask it whether it is a random or a state variable and if it is random, whether it is <strong>rand</strong> or <strong>randc</strong>:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">class</span> <span class="n">rf_variable</span><span class="p">;</span>
  <span class="k">extern</span> <span class="k">function</span> <span class="kt">string</span> <span class="n">get_name</span><span class="p">();</span>
  <span class="k">extern</span> <span class="k">function</span> <span class="kt">bit</span> <span class="n">is_rand</span><span class="p">();</span>
  <span class="k">extern</span> <span class="k">function</span> <span class="n">rand_type_e</span> <span class="n">get_rand_type</span><span class="p">();</span>
  <span class="k">extern</span> <span class="k">function</span> <span class="k">new</span><span class="p">(</span><span class="n">vpiHandle</span> <span class="n">variable</span><span class="p">);</span>
<span class="k">endclass</span>
</code></pre></div></div>

<p>And just as before, this information can be found by traversing the VPI object model, in this case the one defined in Section 37.17:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">function</span> <span class="kt">string</span> <span class="n">rf_variable</span><span class="o">::</span><span class="n">get_name</span><span class="p">();</span>
  <span class="k">return</span> <span class="n">vpi_get_str</span><span class="p">(</span><span class="n">vpiName</span><span class="p">,</span> <span class="n">variable</span><span class="p">);</span>
<span class="k">endfunction</span>

<span class="k">function</span> <span class="kt">bit</span> <span class="n">rf_variable</span><span class="o">::</span><span class="n">is_rand</span><span class="p">();</span>
  <span class="k">return</span> <span class="n">get_rand_type</span><span class="p">()</span> <span class="o">!=</span> <span class="n">NOT_RAND</span><span class="p">;</span>
<span class="k">endfunction</span>

<span class="k">function</span> <span class="n">rand_type_e</span> <span class="n">rf_variable</span><span class="o">::</span><span class="n">get_rand_type</span><span class="p">();</span>
  <span class="n">PLI_INT32</span> <span class="n">rand_type</span> <span class="o">=</span> <span class="n">vpi_get</span><span class="p">(</span><span class="n">vpiRandType</span><span class="p">,</span> <span class="n">variable</span><span class="p">);</span>
  <span class="k">case</span> <span class="p">(</span><span class="n">rand_type</span><span class="p">)</span>
    <span class="n">vpiNotRand</span> <span class="o">:</span> <span class="k">return</span> <span class="n">NOT_RAND</span><span class="p">;</span>
    <span class="n">vpiRand</span> <span class="o">:</span> <span class="k">return</span> <span class="n">RAND</span><span class="p">;</span>
    <span class="n">vpiRandC</span> <span class="o">:</span> <span class="k">return</span> <span class="n">RANDC</span><span class="p">;</span>
    <span class="k">default</span> <span class="o">:</span> <span class="p">$</span><span class="n">fatal</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="s">"Internal error"</span><span class="p">);</span>
  <span class="k">endcase</span>
<span class="k">endfunction</span>
</code></pre></div></div>

<p>As you can see, once we know what information we want to extract, getting it is just a matter of consulting the VPI object models and performing the required traversal operations. Since this is a pretty laborious task, having a cleaner API based on object orientation can certainly help make things more usable.</p>

<p>Let’s look at a simple example of the reflection API in action. Let’s take a simple class definition:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">package</span> <span class="n">some_package</span><span class="p">;</span>

  <span class="kt">class</span> <span class="n">some_class</span><span class="p">;</span>
    <span class="kt">int</span> <span class="n">some_variable</span><span class="p">;</span>
    <span class="k">rand</span> <span class="kt">int</span> <span class="n">some_rand_variable</span><span class="p">;</span>
  <span class="k">endclass</span>

<span class="k">endpackage</span>
</code></pre></div></div>

<p>Using the reflection API, we’re able to print the random type of <code class="language-plaintext highlighter-rouge">some_rand_variable</code>:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">module</span> <span class="n">test</span><span class="p">;</span>
  <span class="k">import</span> <span class="n">reflection</span><span class="o">::*</span><span class="p">;</span>
  <span class="k">import</span> <span class="n">some_package</span><span class="o">::*</span><span class="p">;</span>

  <span class="k">initial</span> <span class="k">begin</span>
    <span class="k">automatic</span> <span class="n">rf_class</span> <span class="n">rf_some_class</span> <span class="o">=</span>
      <span class="n">rf_manager</span><span class="o">::</span><span class="n">get_class_by_name</span><span class="p">(</span><span class="s">"some_class"</span><span class="p">);</span>
    <span class="k">automatic</span> <span class="n">rf_variable</span> <span class="n">rf_some_rand_variable</span> <span class="o">=</span>
      <span class="n">rf_some_class</span><span class="p">.</span><span class="n">get_variable_by_name</span><span class="p">(</span><span class="s">"some_rand_variable"</span><span class="p">);</span>

    <span class="n">rf_some_rand_variable</span><span class="p">.</span><span class="n">print</span><span class="p">();</span>
  <span class="k">end</span>
<span class="k">endmodule</span>
</code></pre></div></div>

<p>We’ve been calling our new package a reflection API, but what we’ve implemented so far is just introspection of the code structure (i.e. compile time aspects). Aside from implementing all relevant queries, to truly say that we’ve implemented introspection, we have to be able to get the values of variables from different objects (i.e. run time aspects). Once we have this, we’ll be able to officially claim that we’ve implemented reflection when we’re also able to set variable values. These steps will be coming soon, so stay tuned.</p>

<p>Experience shows that VPI support, particularly for <em>SystemVerilog</em> constructs, varies from vendor to vendor and strongly depends on how new the simulator version being used is. To check if the package can be used with a particular tool, I’ve written an <a href="https://github.com/tudortimi/reflection/tree/master/unit">“acceptance” test suite</a>. It’s based on <a href="http://www.agilesoc.com/open-source-projects/svunit/">SVUnit</a> and it tries to check if all functionality is available. It’s pretty light at the moment and it supports only one simulator, but it’s a step in the right direction.</p>

<p>You can find the <a href="https://github.com/tudortimi/reflection">reflection</a> package on GitHub. I’ll be adding functionality to it when it’s needed. As I’ve already said a couple of times throughout the post, I’m open to any ideas or contributions that you may have, so don’t hesitate to use the comment section below or to get in touch with me via the <a href="http://blog.verificationgentleman.com/p/contact.html">contact</a> page.</p>]]></content><author><name>Tudor Timi</name></author><category term="Software development" /><category term="SystemVerilog" /><summary type="html"><![CDATA[Reflection is a mechanism that allows “inspection of classes, interfaces, fields and methods at runtime without knowing the names of the interfaces, fields, methods at compile time. It also allows instantiation of new objects and invocation of methods”. In e, using reflection together with define as computed macros allows us to do some really cool stuff.]]></summary></entry><entry><title type="html">An Overview of UVM End-of-Test Mechanisms</title><link href="https://blog.verificationgentleman.com/2016/03/25/an-overview-of-uvm-end-of-test-mechanisms.html" rel="alternate" type="text/html" title="An Overview of UVM End-of-Test Mechanisms" /><published>2016-03-25T21:35:00+01:00</published><updated>2016-03-25T21:35:00+01:00</updated><id>https://blog.verificationgentleman.com/2016/03/25/an-overview-of-uvm-end-of-test-mechanisms</id><content type="html" xml:base="https://blog.verificationgentleman.com/2016/03/25/an-overview-of-uvm-end-of-test-mechanisms.html"><![CDATA[<p>A lot traffic coming from Google to the blog is from searches about setting the UVM drain time. That’s because one of my first posts was about <a href="/2014/04/23/uvm-drain-time-old-fashioned-way.html">how to set the drain time</a> prior to going into the run phase. At the time of writing, this was the third most viewed post.</p>

<p>End-of-test handling in UVM seems to be a topic a lot of people are interested in. In this post we’re going to look at different ways of implementing it.</p>

<p>End-of-test relies on objections. Each component can raise objections during the run phase, meaning that it’s not yet ready to let the test finish. We typically raise an objection in the test, when starting our root sequence:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">class</span> <span class="n">test</span> <span class="k">extends</span> <span class="n">uvm_test</span><span class="p">;</span>
  <span class="kt">virtual</span> <span class="k">task</span> <span class="n">run_phase</span><span class="p">(</span><span class="n">uvm_phase</span> <span class="n">phase</span><span class="p">);</span>
    <span class="n">phase</span><span class="p">.</span><span class="n">raise_objection</span><span class="p">(</span><span class="k">this</span><span class="p">);</span>
    <span class="n">seq</span><span class="p">.</span><span class="n">start</span><span class="p">(</span><span class="n">sequencer</span><span class="p">);</span>
    <span class="n">phase</span><span class="p">.</span><span class="n">drop_objection</span><span class="p">(</span><span class="k">this</span><span class="p">);</span>
  <span class="k">endtask</span>

  <span class="c1">// ...</span>
<span class="k">endclass</span>
</code></pre></div></div>

<p>This means that while the sequence is running, the test will keep going. Once we’ve finished pushing all of our traffic into the DUT, it will stop. This works great for designs without any latency. If our design processes data in the clock cycle it got it, then it’s fine if we just stop the simulation at that point. The isn’t usually the case. Due to the sequential nature of today’s designs, the effect of any kind of transaction fed to the DUT can only be seen one or more clock cycles later. If we stop the simulation at the time the transaction was accepted by the design, then we won’t be able to check what happens as an effect of that transaction.</p>

<p>As an example, let’s take a very boring design. Our DUT will have two APB interfaces, one slave and one master. Whatever comes in on the north (master) interface is going to come out of the south (slave) interface 16 clock cycles later. We’re going to use the <a href="http://www.amiq.com/consulting/2015/03/26/amiq_apb-systemverilog-uvc-for-apb-protocol/">AMIQ APB UVC</a> to talk to our design.</p>

<p>We’ll need to instantiate two agents:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">class</span> <span class="n">env</span> <span class="k">extends</span> <span class="n">uvm_env</span><span class="p">;</span>
  <span class="n">amiq_apb_master_agent</span> <span class="n">master_agent</span><span class="p">;</span>
  <span class="n">amiq_apb_slave_agent</span> <span class="n">slave_agent</span><span class="p">;</span>

  <span class="c1">// ...</span>
<span class="k">endclass</span>
</code></pre></div></div>

<p>I’ll spare you the code for actually instantiating and configuring the agents, since it’s pretty much boilerplate.</p>

<p>What every testbench needs is a scoreboard to check that the DUT is doing what it’s supposed to do. In this case, the scoreboard is pretty trivial. Whenever an item comes from the master agent, we should expect another item with identical characteristics to come from the slave agent.</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">class</span> <span class="n">scoreboard</span> <span class="k">extends</span> <span class="n">uvm_scoreboard</span><span class="p">;</span>
  <span class="cp">`uvm_analysis_imp_decl</span><span class="p">(</span><span class="mi">_</span><span class="n">north</span><span class="p">)</span>
  <span class="cp">`uvm_analysis_imp_decl</span><span class="p">(</span><span class="mi">_</span><span class="n">south</span><span class="p">)</span>

  <span class="n">uvm_analysis_imp_north</span> <span class="p">#(</span><span class="n">amiq_apb_mon_item</span><span class="p">,</span> <span class="n">scoreboard</span><span class="p">)</span> <span class="n">north_aimp</span><span class="p">;</span>
  <span class="n">uvm_analysis_imp_south</span> <span class="p">#(</span><span class="n">amiq_apb_mon_item</span><span class="p">,</span> <span class="n">scoreboard</span><span class="p">)</span> <span class="n">south_aimp</span><span class="p">;</span>

  <span class="c1">// ...</span>
<span class="k">endclass</span>
</code></pre></div></div>

<p>Since it can be a while until a south side item comes, in the meantime we’ll need to buffer the north side items in a queue. The APB UVC sends out two items per transfer through its analysis port, one for the setup phase and another for the access phase. I don’t particularly like this approach, since it forces us to implement logic to throw out the setup phase item (two analysis ports would have been better):</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">class</span> <span class="n">scoreboard</span> <span class="k">extends</span> <span class="n">uvm_scoreboard</span><span class="p">;</span>
  <span class="k">protected</span> <span class="kt">int</span> <span class="kt">unsigned</span> <span class="n">num_seen_north_items</span><span class="p">;</span>

  <span class="k">protected</span> <span class="n">amiq_apb_mon_item</span> <span class="n">item_stream</span><span class="p">[$];</span>


  <span class="kt">virtual</span> <span class="k">function</span> <span class="kt">void</span> <span class="n">write_north</span><span class="p">(</span><span class="n">amiq_apb_mon_item</span> <span class="n">item</span><span class="p">);</span>
    <span class="n">num_seen_north_items</span><span class="o">++</span><span class="p">;</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">num_seen_north_items</span> <span class="o">%</span> <span class="mi">2</span> <span class="o">==</span> <span class="mi">1</span><span class="p">)</span>
      <span class="k">return</span><span class="p">;</span>

    <span class="cp">`uvm_info</span><span class="p">(</span><span class="s">"WRNORTH"</span><span class="p">,</span> <span class="s">"Got a north item"</span><span class="p">,</span> <span class="n">UVM_NONE</span><span class="p">)</span>
    <span class="n">item_stream</span><span class="p">.</span><span class="n">push_back</span><span class="p">(</span><span class="n">item</span><span class="p">);</span>
  <span class="k">endfunction</span>

  <span class="c1">// ...</span>
<span class="k">endclass</span>
</code></pre></div></div>

<p>When a south side item comes, we’ll need to compare it with the first item in the queue:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">class</span> <span class="n">scoreboard</span> <span class="k">extends</span> <span class="n">uvm_scoreboard</span><span class="p">;</span>
  <span class="k">protected</span> <span class="kt">int</span> <span class="kt">unsigned</span> <span class="n">num_seen_south_items</span><span class="p">;</span>

  <span class="k">protected</span> <span class="n">amiq_apb_mon_item</span> <span class="n">item_stream</span><span class="p">[$];</span>


  <span class="kt">virtual</span> <span class="k">function</span> <span class="kt">void</span> <span class="n">write_south</span><span class="p">(</span><span class="n">amiq_apb_mon_item</span> <span class="n">item</span><span class="p">);</span>
    <span class="n">num_seen_south_items</span><span class="o">++</span><span class="p">;</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">num_seen_south_items</span> <span class="o">%</span> <span class="mi">2</span> <span class="o">==</span> <span class="mi">1</span><span class="p">)</span>
      <span class="k">return</span><span class="p">;</span>

    <span class="cp">`uvm_info</span><span class="p">(</span><span class="s">"WRSOUTH"</span><span class="p">,</span> <span class="s">"Got a south item"</span><span class="p">,</span> <span class="n">UVM_NONE</span><span class="p">)</span>
    <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">item</span><span class="p">.</span><span class="n">compare</span><span class="p">(</span><span class="n">item_stream</span><span class="p">.</span><span class="n">pop_front</span><span class="p">()))</span>
      <span class="cp">`uvm_error</span><span class="p">(</span><span class="s">"DUTERR"</span><span class="p">,</span> <span class="s">"Mismatch"</span><span class="p">)</span>
  <span class="k">endfunction</span>

  <span class="c1">// ..</span>
<span class="k">endclass</span>
</code></pre></div></div>

<p>What we absolutely need to check is that at the end of the simulation there aren’t any outstanding north side items that didn’t yet make it to the south side. This means our queue must be empty. A great place to put this check is the <code class="language-plaintext highlighter-rouge">check_phase(...)</code> function:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">class</span> <span class="n">scoreboard</span> <span class="k">extends</span> <span class="n">uvm_scoreboard</span><span class="p">;</span>
  <span class="kt">virtual</span> <span class="k">function</span> <span class="kt">void</span> <span class="n">check_phase</span><span class="p">(</span><span class="n">uvm_phase</span> <span class="n">phase</span><span class="p">);</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">item_stream</span><span class="p">.</span><span class="nb">size</span><span class="p">()</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)</span>
      <span class="cp">`uvm_error</span><span class="p">(</span><span class="s">"DUTERR"</span><span class="p">,</span> <span class="s">"There are still unchecked items"</span><span class="p">)</span>
  <span class="k">endfunction</span>

  <span class="c1">// ...</span>
<span class="k">endclass</span>
</code></pre></div></div>

<p>Here’s where gracious test termination becomes important. If we just stop the simulation once the last north side item was sent, we’re going have at least one item in our queue, which will cause the test to fail. This means we can’t just simply start our sequence in this way:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">class</span> <span class="n">test</span> <span class="k">extends</span> <span class="n">uvm_test</span><span class="p">;</span>
  <span class="kt">virtual</span> <span class="k">task</span> <span class="n">run_phase</span><span class="p">(</span><span class="n">uvm_phase</span> <span class="n">phase</span><span class="p">);</span>
    <span class="n">apb_pipeline_tb</span><span class="o">::</span><span class="n">pipeline_sequence</span> <span class="n">seq</span> <span class="o">=</span>
      <span class="n">apb_pipeline_tb</span><span class="o">::</span><span class="n">pipeline_sequence</span><span class="o">::</span><span class="n">type_id</span><span class="o">::</span><span class="n">create</span><span class="p">(</span><span class="s">"seq"</span><span class="p">,</span> <span class="k">this</span><span class="p">);</span>

    <span class="n">phase</span><span class="p">.</span><span class="n">raise_objection</span><span class="p">(</span><span class="k">this</span><span class="p">);</span>
    <span class="n">seq</span><span class="p">.</span><span class="n">start</span><span class="p">(</span><span class="n">tb_env</span><span class="p">.</span><span class="n">master_agent</span><span class="p">.</span><span class="n">sequencer</span><span class="p">);</span>
    <span class="n">phase</span><span class="p">.</span><span class="n">drop_objection</span><span class="p">(</span><span class="k">this</span><span class="p">);</span>
  <span class="k">endtask</span>

  <span class="c1">// ...</span>
<span class="k">endclass</span>
</code></pre></div></div>

<p>We need to make sure that the objection gets dropped once the last item comes out through the south side APB interface. The naïve approach would be to add a delay inside the test between the sequence finishing and dropping the objection:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">class</span> <span class="n">test_delay</span> <span class="k">extends</span> <span class="n">test</span><span class="p">;</span>
  <span class="kt">virtual</span> <span class="k">task</span> <span class="n">run_phase</span><span class="p">(</span><span class="n">uvm_phase</span> <span class="n">phase</span><span class="p">);</span>
    <span class="n">apb_pipeline_tb</span><span class="o">::</span><span class="n">pipeline_sequence</span> <span class="n">seq</span> <span class="o">=</span>
      <span class="n">apb_pipeline_tb</span><span class="o">::</span><span class="n">pipeline_sequence</span><span class="o">::</span><span class="n">type_id</span><span class="o">::</span><span class="n">create</span><span class="p">(</span><span class="s">"seq"</span><span class="p">,</span> <span class="k">this</span><span class="p">);</span>

    <span class="n">phase</span><span class="p">.</span><span class="n">raise_objection</span><span class="p">(</span><span class="k">this</span><span class="p">);</span>
    <span class="n">seq</span><span class="p">.</span><span class="n">start</span><span class="p">(</span><span class="n">tb_env</span><span class="p">.</span><span class="n">master_agent</span><span class="p">.</span><span class="n">sequencer</span><span class="p">);</span>

    <span class="p">#(</span><span class="mi">16</span> <span class="o">*</span> <span class="mi">2</span><span class="p">);</span>

    <span class="n">phase</span><span class="p">.</span><span class="n">drop_objection</span><span class="p">(</span><span class="k">this</span><span class="p">);</span>
  <span class="k">endtask</span>

  <span class="c1">// ...</span>
<span class="k">endclass</span>
</code></pre></div></div>

<p>This is going to work, though it might need an extra time step to avoid any race conditions when stopping the simulation (because the south side monitor might not get a chance to publish its item). There are a few drawbacks, though:</p>

<ol>
  <li>
    <p>We’re going to have to add such a delay to each test we write. Once our designers decide that they need a 17 cycle deep pipeline, we’re going to have to modify each and every one of these tests. This can, of course, be solved by writing a function that drops the objection and applies the delay beforehand.</p>
  </li>
  <li>
    <p>We’ve implemented the delay in terms of simulation steps, when we’re actually interested in clock cycles (hence the multiplication with 2 - a clock cycle takes two simulation time steps). The same argument applies also if we were to wait for a certain number of time units. If someone decides that we need a longer clock, we’re going to have to update the delays. This can also be solved by sending the APB clock to the test and using it for the delay. This is easier said than done in <em>SystemVerilog</em>, since what this entails is defining an interface, instantiating it, putting it into the config DB and getting it in the test.</p>
  </li>
  <li>
    <p>For complicated designs it might be difficult, if not impossible, to figure out how much time to wait before dropping the objection.</p>
  </li>
  <li>
    <p>It’s very easy to forget to add the delay, leading to wasted debug time.</p>
  </li>
</ol>

<p>What UVM also provides is a “drain time” mechanism. After all objections have been dropped, the simulation end is delayed by the drain time configured by the user. The cool thing about it is that it can be set once in the base test and other tests don’t need to take care of it anymore. A good place to do it is before the run phase starts, in either one of the <code class="language-plaintext highlighter-rouge">end_of_elaboration_phase(...)</code> or the <code class="language-plaintext highlighter-rouge">start_of_simulation_phase(...)</code> functions:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">class</span> <span class="n">test_drain_time</span> <span class="k">extends</span> <span class="n">test</span><span class="p">;</span>
  <span class="kt">virtual</span> <span class="k">function</span> <span class="kt">void</span> <span class="n">end_of_elaboration_phase</span><span class="p">(</span><span class="n">uvm_phase</span> <span class="n">phase</span><span class="p">);</span>
    <span class="n">uvm_phase</span> <span class="n">run_phase</span> <span class="o">=</span> <span class="n">uvm_run_phase</span><span class="o">::</span><span class="n">get</span><span class="p">();</span>
    <span class="n">run_phase</span><span class="p">.</span><span class="n">phase_done</span><span class="p">.</span><span class="n">set_drain_time</span><span class="p">(</span><span class="k">this</span><span class="p">,</span> <span class="mi">16</span> <span class="o">*</span> <span class="mi">2</span><span class="p">);</span>
  <span class="k">endfunction</span>

  <span class="c1">// ...</span>
<span class="k">endclass</span>
</code></pre></div></div>

<p>The drawback here is, as in the previous case, that we are specifying the duration in simulation steps, not clock cycles. Moreover, in this case, the actual delay will be done by code in the UVM package. This means the time settings used when compiling UVM will be taken into account, so it might get really funky when working with a pre-compiled library from a vendor (which is usually the case).</p>

<p>The best thing would be if the scoreboard itself could decide when to allow the test to stop. What it could do is raise an objection whenever a north side item is received. This means that the DUT is processing something. Once a south side item comes out, it can drop an objection. Since (ideally) the number of north and south side items should match, once the DUT is done processing everything the scoreboard should drop all of its objections:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">class</span> <span class="n">scoreboard_with_objection</span> <span class="k">extends</span> <span class="n">apb_pipeline_tb</span><span class="o">::</span><span class="n">scoreboard</span><span class="p">;</span>
  <span class="kt">virtual</span> <span class="k">function</span> <span class="kt">void</span> <span class="n">write_north</span><span class="p">(</span><span class="n">amiq_apb_pkg</span><span class="o">::</span><span class="n">amiq_apb_mon_item</span> <span class="n">item</span><span class="p">);</span>
    <span class="n">uvm_phase</span> <span class="n">run_phase</span><span class="p">;</span>

    <span class="k">super</span><span class="p">.</span><span class="n">write_north</span><span class="p">(</span><span class="n">item</span><span class="p">);</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">num_seen_north_items</span> <span class="o">%</span> <span class="mi">2</span> <span class="o">==</span> <span class="mi">1</span><span class="p">)</span>
      <span class="k">return</span><span class="p">;</span>

    <span class="n">run_phase</span> <span class="o">=</span> <span class="n">uvm_run_phase</span><span class="o">::</span><span class="n">get</span><span class="p">();</span>
    <span class="n">run_phase</span><span class="p">.</span><span class="n">raise_objection</span><span class="p">(</span><span class="k">this</span><span class="p">);</span>
  <span class="k">endfunction</span>


  <span class="kt">virtual</span> <span class="k">function</span> <span class="kt">void</span> <span class="n">write_south</span><span class="p">(</span><span class="n">amiq_apb_pkg</span><span class="o">::</span><span class="n">amiq_apb_mon_item</span> <span class="n">item</span><span class="p">);</span>
    <span class="n">uvm_phase</span> <span class="n">run_phase</span><span class="p">;</span>

    <span class="k">super</span><span class="p">.</span><span class="n">write_south</span><span class="p">(</span><span class="n">item</span><span class="p">);</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">num_seen_south_items</span> <span class="o">%</span> <span class="mi">2</span> <span class="o">==</span> <span class="mi">1</span><span class="p">)</span>
      <span class="k">return</span><span class="p">;</span>

    <span class="n">run_phase</span> <span class="o">=</span> <span class="n">uvm_run_phase</span><span class="o">::</span><span class="n">get</span><span class="p">();</span>
    <span class="n">run_phase</span><span class="p">.</span><span class="n">drop_objection</span><span class="p">(</span><span class="k">this</span><span class="p">);</span>
  <span class="k">endfunction</span>

  <span class="c1">// ...</span>
<span class="k">endclass</span>
</code></pre></div></div>

<p>The great thing about this approach is that it works regardless of what pipeline depth we have. The only reason why someone might not want to implement a scoreboard like this is if they hang out too much on <a href="https://verificationacademy.com/">Verification Academy</a>. The guys at Mentor Graphics say that raising objections in any place other than the test is a performance killer, particularly if its done on a per item basis, like we have here. This is because objections have to propagate throughout the hierarchy, which can take a significant toll on the simulator. In a toy example like this one it’s probably not going to make much of a dent, but I can imagine that things can go overboard fast when dealing with complicated designs with many interfaces. With the (rather) new UVM 1.2 release, objections have gotten leaner, so the argument might not hold up anymore.</p>

<p>If you have a really big design and you’re stuck using UVM 1.1, don’t despair! There is a way to leave the scoreboard in control of when to end the test, without having to raise and drop objections for each item it gets. Each <code class="language-plaintext highlighter-rouge">uvm_component</code> has a <code class="language-plaintext highlighter-rouge">phase_ready_to_end(...)</code> function that is called before the phase is stopped. If our scoreboard still has items queued when the test sequence finishes, it can raise an objection to delay the end of the simulation. Once the queue becomes empty, it can drop the objection and allow the test to end:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">class</span> <span class="n">scoreboard_with_phase_ready_to_end</span> <span class="k">extends</span> <span class="n">apb_pipeline_tb</span><span class="o">::</span><span class="n">scoreboard</span><span class="p">;</span>
  <span class="kt">virtual</span> <span class="k">function</span> <span class="kt">void</span> <span class="n">phase_ready_to_end</span><span class="p">(</span><span class="n">uvm_phase</span> <span class="n">phase</span><span class="p">);</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">phase</span><span class="p">.</span><span class="n">get_name</span> <span class="o">!=</span> <span class="s">"run"</span><span class="p">)</span>
      <span class="k">return</span><span class="p">;</span>

    <span class="k">if</span> <span class="p">(</span><span class="n">item_stream</span><span class="p">.</span><span class="nb">size</span><span class="p">()</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)</span> <span class="k">begin</span>
      <span class="n">phase</span><span class="p">.</span><span class="n">raise_objection</span><span class="p">(</span><span class="k">this</span><span class="p">);</span>
      <span class="k">fork</span>
        <span class="n">delay_phase_end</span><span class="p">(</span><span class="n">phase</span><span class="p">);</span>
      <span class="k">join_none</span>
    <span class="k">end</span>
  <span class="k">endfunction</span>


  <span class="kt">virtual</span> <span class="k">task</span> <span class="n">delay_phase_end</span><span class="p">(</span><span class="n">uvm_phase</span> <span class="n">phase</span><span class="p">);</span>
    <span class="k">wait</span> <span class="p">(</span><span class="n">item_stream</span><span class="p">.</span><span class="nb">size</span><span class="p">()</span> <span class="o">==</span> <span class="mi">0</span><span class="p">);</span>
    <span class="n">phase</span><span class="p">.</span><span class="n">drop_objection</span><span class="p">(</span><span class="k">this</span><span class="p">);</span>
  <span class="k">endtask</span>

  <span class="c1">// ...</span>
<span class="k">endclass</span>
</code></pre></div></div>

<p>This combines the best of both worlds. It works regardless of pipeline depth, since we don’t have to specify any kind of delay. It’s also very efficient in terms of performance, since we don’t need to execute anything for each item that the scoreboard receives. We only need to fork the drain task in the last stage of the simulation, which should have a negligible impact on the run time. There is one caveat, though. In more complicated testbenches, it might be the case that multiple components want to delay the end of the test. This could lead to situations where all objections for the run phase (for example) are dropped, <code class="language-plaintext highlighter-rouge">phase_ready_to_end(...)</code> gets called and a component decides to prolong the phase by raising another objection, eventually drops it, <code class="language-plaintext highlighter-rouge">phase_ready_to_end(...)</code> gets called again, another component wants to prolong the phase, and so on. If this process repeats too many times, a fatal error is flagged, as mentioned in <a href="https://verificationacademy.com/forums/uvm/why-are-you-recommending-phasereadytoend-when-it-has-limit-20-calls">this thread</a>. Such a situation shouldn’t happened very often in practice.</p>

<p>These are the ways of handling end-of-test that currently come to mind. If I missed anything, do let me know in the comments section. If you want to experiment, the code can be found on <a href="https://github.com/tudortimi/verification-gentleman-blog-code/tree/master/uvm_end_of_test">GitHub</a>. Out of all outlined methods, using <code class="language-plaintext highlighter-rouge">phase_ready_to_end(...)</code> seems to be the best by far. I’m definitely using it in my future projects.</p>]]></content><author><name>Tudor Timi</name></author><category term="SystemVerilog" /><category term="UVM" /><summary type="html"><![CDATA[A lot traffic coming from Google to the blog is from searches about setting the UVM drain time. That’s because one of my first posts was about how to set the drain time prior to going into the run phase. At the time of writing, this was the third most viewed post.]]></summary></entry><entry><title type="html">Registering Abstract Classes with the UVM Factory</title><link href="https://blog.verificationgentleman.com/2016/02/14/abstract-classes-uvm-factory.html" rel="alternate" type="text/html" title="Registering Abstract Classes with the UVM Factory" /><published>2016-02-14T18:18:00+01:00</published><updated>2016-02-14T18:18:00+01:00</updated><id>https://blog.verificationgentleman.com/2016/02/14/abstract-classes-uvm-factory</id><content type="html" xml:base="https://blog.verificationgentleman.com/2016/02/14/abstract-classes-uvm-factory.html"><![CDATA[<p>Every now and again I stumble upon a situation where it’s natural to use an abstract class. A typical example is when working with parameterized classes and wanting to swap parameterizations:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">virtual</span> <span class="kt">class</span> <span class="n">some_abstract_component</span> <span class="k">extends</span> <span class="n">uvm_component</span><span class="p">;</span>
  <span class="k">pure</span> <span class="kt">virtual</span> <span class="k">function</span> <span class="kt">void</span> <span class="n">do_stuff</span><span class="p">();</span>

  <span class="kt">virtual</span> <span class="k">task</span> <span class="n">run_phase</span><span class="p">(</span><span class="n">uvm_phase</span> <span class="n">phase</span><span class="p">);</span>
    <span class="n">do_stuff</span><span class="p">();</span>
  <span class="k">endtask</span>
<span class="k">endclass</span>


<span class="kt">class</span> <span class="n">some_concrete_param_component</span> <span class="p">#(</span><span class="k">type</span> <span class="n">T</span> <span class="o">=</span> <span class="kt">int</span><span class="p">)</span> <span class="k">extends</span>
  <span class="n">some_abstract_component</span><span class="p">;</span>

  <span class="kt">virtual</span> <span class="k">function</span> <span class="kt">void</span> <span class="n">do_stuff</span><span class="p">();</span>
    <span class="p">$</span><span class="nb">display</span><span class="p">(</span><span class="s">"I'm doing %s stuff"</span><span class="p">,</span> <span class="p">$</span><span class="nb">typename</span><span class="p">(</span><span class="n">T</span><span class="p">));</span>
  <span class="k">endfunction</span>
<span class="k">endclass</span>
</code></pre></div></div>

<p>This is something we used in the post on <a href="/2015/06/29/even-more-ideas-on-coverage-extensibility.html">coverage extensibility</a>, when we talked about having policy classes as parameters to coverage collector components.</p>

<p>Each parameterization of a class creates an own inheritance tree independent of the others. If we want to be able to store any parameterization in a variable, we need a common base class:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">some_abstract_component</span> <span class="n">comp</span><span class="p">;</span>
<span class="n">some_concrete_param_component</span> <span class="p">#(</span><span class="kt">bit</span><span class="p">)</span> <span class="n">bit_comp</span> <span class="o">=</span> <span class="k">new</span><span class="p">();</span>
<span class="n">some_concrete_param_component</span> <span class="p">#(</span><span class="kt">real</span><span class="p">)</span> <span class="n">real_comp</span> <span class="o">=</span> <span class="k">new</span><span class="p">();</span>

<span class="c1">// allowed</span>
<span class="n">comp</span> <span class="o">=</span> <span class="n">bit_comp</span><span class="p">;</span>

<span class="c1">// also allowed</span>
<span class="n">comp</span> <span class="o">=</span> <span class="n">real_comp</span><span class="p">;</span>
</code></pre></div></div>

<p>By tagging the base class as <strong>virtual</strong> we’ve marked it as incomplete. We’ve declared that it can do something (via the <code class="language-plaintext highlighter-rouge">do_stuff()</code> function), but we haven’t yet told the compiler how it can do it. This is left to sub-classes. We want to be able to easily swap parameterizations, without resorting to a big <strong>if/else</strong> cascade or a long <strong>case</strong> statement. This is what the UVM factory is for. Assuming that both types are registered with the factory we could do the following:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">some_abstract_component</span> <span class="n">comp</span> <span class="o">=</span> <span class="n">some_abstract_component</span><span class="o">::</span><span class="n">type_id</span><span class="o">::</span><span class="n">create</span><span class="p">(...);</span>

<span class="c1">// In a test, before creating 'comp'</span>
<span class="n">some_abstract_component</span><span class="o">::</span><span class="n">type_id</span><span class="o">::</span><span class="n">set_type_override</span><span class="p">(</span>
  <span class="n">some_concrete_param_component</span> <span class="p">#(</span><span class="kt">bit</span><span class="p">)</span><span class="o">::</span><span class="n">get_type</span><span class="p">());</span>

<span class="c1">// In a different test, also before creating 'comp'</span>
<span class="n">some_abstract_component</span><span class="o">::</span><span class="n">type_id</span><span class="o">::</span><span class="n">set_type_override</span><span class="p">(</span>
  <span class="n">some_concrete_param_component</span> <span class="p">#(</span><span class="kt">real</span><span class="p">)</span><span class="o">::</span><span class="n">get_type</span><span class="p">());</span>
</code></pre></div></div>

<p>The type overrides let the factory know that wherever we wanted to instantiate <code class="language-plaintext highlighter-rouge">some_abstract_component</code> it should instantiate the overridden type instead. We can’t (officially) do this out of the box.</p>

<p>Depending on your simulator you can see one of the following outcomes when using the <code class="language-plaintext highlighter-rouge">uvm_object_utils</code> macro with a virtual class:</p>

<ol>
  <li>the code compiles without any problems; if the virtual class constructor ends up being called (which would happen if we’d forget to set an override) a fatal error is issued</li>
  <li>you get a warning that you’re trying to instantiate a virtual class, but the code still compiles; as above, actually calling the constructor is not allowed</li>
  <li>the compiler stops with an error saying that it’s illegal to instantiate a virtual class</li>
</ol>

<p>Out of the three above, only outcome number 3 follows the LRM strictly. In the interest of portability, we shouldn’t be writing code that relies on vendor “features” to compile. This is the whole reason why we as an industry have moved to <em>SystemVerilog</em>, isn’t it?</p>

<p>Let’s look at what the uvm_component_utils macro expands to:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">virtual</span> <span class="kt">class</span> <span class="n">some_abstract_class</span> <span class="k">extends</span> <span class="n">uvm_component</span><span class="p">;</span>
  <span class="c1">// ...</span>

  <span class="c1">// `uvm_component_utils(some_abstract_class)</span>
  <span class="cp">`m_uvm_component_registry_internal</span><span class="p">(</span><span class="n">some_abstract_class</span><span class="p">,</span> <span class="n">some_abstract_class</span><span class="p">)</span>
  <span class="cp">`m_uvm_get_type_name_func</span><span class="p">(</span><span class="n">some_abstract_class</span><span class="p">)</span>
<span class="k">endclass</span>
</code></pre></div></div>

<p>Let’s dig deeper and see how factory registration is done by also expanding the <code class="language-plaintext highlighter-rouge">m_uvm_component_registry_internal(...)</code> macro:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">virtual</span> <span class="kt">class</span> <span class="n">some_abstract_class</span> <span class="k">extends</span> <span class="n">uvm_component</span><span class="p">;</span>
  <span class="c1">// ...</span>

  <span class="c1">// `m_uvm_component_registry_internal(some_abstract_class, ...)</span>
  <span class="k">typedef</span> <span class="n">uvm_component_registry</span> <span class="p">#(</span><span class="n">some_abstract_class</span><span class="p">,</span>
    <span class="s">"some_abstract_class"</span><span class="p">)</span> <span class="n">type_id</span><span class="p">;</span>

  <span class="kt">static</span> <span class="k">function</span> <span class="n">type_id</span> <span class="n">get_type</span><span class="p">();</span>
    <span class="k">return</span> <span class="n">type_id</span><span class="o">::</span><span class="n">get</span><span class="p">();</span>
  <span class="k">endfunction</span>

  <span class="kt">virtual</span> <span class="k">function</span> <span class="n">uvm_object_wrapper</span> <span class="n">get_object_type</span><span class="p">();</span>
    <span class="k">return</span> <span class="n">type_id</span><span class="o">::</span><span class="n">get</span><span class="p">();</span>
  <span class="k">endfunction</span>
<span class="k">endclass</span>
</code></pre></div></div>

<p>The veil of secrecy is being lifted. The ominous <code class="language-plaintext highlighter-rouge">type_id</code> that we’ve been using is actually a <strong>typedef</strong> that is shorthand for a parameterization of <code class="language-plaintext highlighter-rouge">uvm_component_registry</code>. If we open up its source code we can find the offending function:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">class</span> <span class="n">uvm_component_registry</span> <span class="p">#(...)</span> <span class="k">extends</span> <span class="n">uvm_object_wrapper</span><span class="p">;</span>

  <span class="c1">// After elaboration with 'some_abstract_class' as an parameter</span>
  <span class="kt">virtual</span> <span class="k">function</span> <span class="n">uvm_component</span> <span class="n">create_component</span> <span class="p">(</span><span class="kt">string</span> <span class="n">name</span><span class="p">,</span>
                                                   <span class="n">uvm_component</span> <span class="n">parent</span><span class="p">);</span>
    <span class="n">some_abstract_class</span> <span class="n">obj</span><span class="p">;</span>
    <span class="n">obj</span> <span class="o">=</span> <span class="k">new</span><span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="n">parent</span><span class="p">);</span>  <span class="c1">// !!!</span>
    <span class="k">return</span> <span class="n">obj</span><span class="p">;</span>
  <span class="k">endfunction</span>

  <span class="c1">// ...</span>
<span class="k">endclass</span>
</code></pre></div></div>

<p>The <code class="language-plaintext highlighter-rouge">create_component(...)</code> function calls <code class="language-plaintext highlighter-rouge">new(...)</code> to get an object of the type its parameterized with, which in our case is <code class="language-plaintext highlighter-rouge">some_abstract_class</code>. Because of this, we can’t parameterize <code class="language-plaintext highlighter-rouge">uvm_component_registry</code> with a virtual class. The same point also applies for classes that inherit directly from <code class="language-plaintext highlighter-rouge">uvm_object</code> and its corresponding <code class="language-plaintext highlighter-rouge">uvm_object_registry</code>.</p>

<p>Before we continue, it might be a good idea to take a step back and look at what exactly happens when we create an object using the factory. The first cog in the machine is the <code class="language-plaintext highlighter-rouge">uvm_object_wrapper</code> class, which contains two methods, <code class="language-plaintext highlighter-rouge">create_object(...)</code> and <code class="language-plaintext highlighter-rouge">create_component(...)</code>. The class itself is <strong>virtual</strong> and these methods are almost <strong>pure virtual</strong> (in the sense that they don’t do anything):</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">virtual</span> <span class="kt">class</span> <span class="n">uvm_object_wrapper</span><span class="p">;</span>
  <span class="kt">virtual</span> <span class="k">function</span> <span class="n">uvm_object</span> <span class="n">create_object</span> <span class="p">(</span><span class="kt">string</span> <span class="n">name</span><span class="o">=</span><span class="s">""</span><span class="p">);</span>
    <span class="k">return</span> <span class="k">null</span><span class="p">;</span>
  <span class="k">endfunction</span>

  <span class="kt">virtual</span> <span class="k">function</span> <span class="n">uvm_component</span> <span class="n">create_component</span> <span class="p">(</span><span class="kt">string</span> <span class="n">name</span><span class="p">,</span>
                                                   <span class="n">uvm_component</span> <span class="n">parent</span><span class="p">);</span>
    <span class="k">return</span> <span class="k">null</span><span class="p">;</span>
  <span class="k">endfunction</span>
<span class="k">endclass</span>
</code></pre></div></div>

<p>A class that can be created by the factory must have a corresponding <code class="language-plaintext highlighter-rouge">uvm_object_wrapper</code> associated with it, that implements the corresponding <code class="language-plaintext highlighter-rouge">create_*(...)</code> function to call that class’s constructor, thereby returning an instance of that class:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">class</span> <span class="n">some_class</span> <span class="k">extends</span> <span class="n">uvm_object</span><span class="p">;</span>
  <span class="k">extern</span> <span class="k">function</span> <span class="k">new</span><span class="p">(</span><span class="kt">string</span> <span class="n">name</span><span class="p">);</span>
<span class="k">endclass</span>

<span class="kt">class</span> <span class="n">some_class_wrapper</span> <span class="k">extends</span> <span class="n">uvm_object_wrapper</span><span class="p">;</span>
  <span class="kt">virtual</span> <span class="k">function</span> <span class="n">uvm_object</span> <span class="n">create_object</span><span class="p">(</span><span class="kt">string</span> <span class="n">name</span><span class="p">);</span>
    <span class="n">some_class</span> <span class="n">obj</span> <span class="o">=</span> <span class="k">new</span><span class="p">(</span><span class="n">name</span><span class="p">);</span>
    <span class="k">return</span> <span class="n">obj</span><span class="p">;</span>
  <span class="k">endfunction</span>
<span class="k">endclass</span>
</code></pre></div></div>

<p>The factory can create an instance of <code class="language-plaintext highlighter-rouge">some_class</code> by using its wrapper:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">class</span> <span class="n">uvm_factory</span><span class="p">;</span>
  <span class="k">function</span> <span class="n">uvm_object</span> <span class="n">create_object_by_type</span><span class="p">(</span><span class="n">uvm_object_wrapper</span> <span class="n">requested_type</span><span class="p">,</span>
    <span class="kt">string</span> <span class="n">name</span> <span class="o">=</span> <span class="s">""</span>
  <span class="p">);</span>
    <span class="c1">// ...</span>
    <span class="k">return</span> <span class="n">requesed_type</span><span class="p">.</span><span class="n">create_object</span><span class="p">(</span><span class="n">name</span><span class="p">);</span>
  <span class="k">endfunction</span>

  <span class="c1">// ...</span>
<span class="k">endclass</span>
</code></pre></div></div>

<p>It would be rather boring if this is all it would do, because what would then be the point of using the factory? We could just as easily create an object in our user code. What the factory first does is it checks if there is an override in place. If there is, instead of calling <code class="language-plaintext highlighter-rouge">create_object(...)</code> on the wrapper it got as an argument, it’s going to call it on the wrapper of the overriding type:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">class</span> <span class="n">uvm_factory</span><span class="p">;</span>
  <span class="k">function</span> <span class="n">uvm_object</span> <span class="n">create_object_by_type</span><span class="p">(</span><span class="n">uvm_object_wrapper</span> <span class="n">requested_type</span><span class="p">,</span>
    <span class="kt">string</span> <span class="n">name</span> <span class="o">=</span> <span class="s">""</span>
  <span class="p">);</span>
    <span class="n">uvm_object_wrapper</span> <span class="n">returned_type</span><span class="p">;</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">has_override</span><span class="p">(</span><span class="n">requested_type</span><span class="p">))</span>
      <span class="n">returned_type</span> <span class="o">=</span> <span class="n">get_override</span><span class="p">(</span><span class="n">requested_type</span><span class="p">);</span>
    <span class="k">else</span>
      <span class="n">returned_type</span> <span class="o">=</span> <span class="n">requested_type</span><span class="p">;</span>
    <span class="k">return</span> <span class="n">returned_type</span><span class="p">.</span><span class="n">create_object</span><span class="p">(</span><span class="n">name</span><span class="p">);</span>
  <span class="k">endfunction</span>

  <span class="c1">// ...</span>
<span class="k">endclass</span>
</code></pre></div></div>

<p>For simplicity, we can imagine that the lookup mechanism works like a look up table, which maps one wrapper to a potentially different wrapper.</p>

<p>Let’s go back to how wrappers are defined. What we’ve looked at up to now are the classes behind the curtain of encapsulation, that we as users don’t normally see. As the task of registering a class with the factory is something that we need to do quite often, the nice people at Accellera defined some classes that can handle this easily: <code class="language-plaintext highlighter-rouge">uvm_object_registry</code> and <code class="language-plaintext highlighter-rouge">uvm_component_registry</code>. These are sub-classes of <code class="language-plaintext highlighter-rouge">uvm_object_wrapper</code> and parameterized with the class they are supposed to create:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">class</span> <span class="n">uvm_object_registry</span> <span class="p">#(</span><span class="k">type</span> <span class="n">T</span><span class="o">=</span><span class="n">uvm_object</span><span class="p">)</span> <span class="k">extends</span> <span class="n">uvm_object_wrapper</span><span class="p">;</span>
  <span class="k">typedef</span> <span class="n">uvm_object_registry</span> <span class="p">#(</span><span class="n">T</span><span class="p">)</span> <span class="n">this_type</span><span class="p">;</span>

  <span class="c1">// ...</span>
<span class="k">endclass</span>
</code></pre></div></div>

<p>This way, these classes can provide generic implementations of <code class="language-plaintext highlighter-rouge">create_object(...)</code> and <code class="language-plaintext highlighter-rouge">create_component(...)</code>, respectively:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">class</span> <span class="n">uvm_object_registry</span> <span class="p">#(</span><span class="k">type</span> <span class="n">T</span><span class="o">=</span><span class="n">uvm_object</span><span class="p">)</span> <span class="k">extends</span> <span class="n">uvm_object_wrapper</span><span class="p">;</span>
  <span class="c1">// ...</span>

  <span class="kt">virtual</span> <span class="k">function</span> <span class="n">uvm_object</span> <span class="n">create_object</span><span class="p">(</span><span class="kt">string</span> <span class="n">name</span><span class="p">);</span>
    <span class="n">T</span> <span class="n">obj</span> <span class="o">=</span> <span class="k">new</span><span class="p">(</span><span class="n">name</span><span class="p">);</span>
    <span class="k">return</span> <span class="n">obj</span><span class="p">;</span>
  <span class="k">endfunction</span>
<span class="k">endclass</span>
</code></pre></div></div>

<p>By having the class of interest as a parameter, we avoid having to always declare a sub-class for each new class we want to use with the factory. The <code class="language-plaintext highlighter-rouge">*_registry</code> classes also provide the famous <code class="language-plaintext highlighter-rouge">create(...)</code> function we’ve been told to always call instead of <code class="language-plaintext highlighter-rouge">new(...)</code>. This function gets an instance of the registry class its being called on and passes it to the factory to do the actual creation:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">class</span> <span class="n">uvm_object_registry</span> <span class="p">#(</span><span class="k">type</span> <span class="n">T</span><span class="o">=</span><span class="n">uvm_object</span><span class="p">)</span> <span class="k">extends</span> <span class="n">uvm_object_wrapper</span><span class="p">;</span>
  <span class="c1">// ...</span>

  <span class="kt">static</span> <span class="k">function</span> <span class="n">T</span> <span class="n">create</span><span class="p">(</span><span class="kt">string</span> <span class="n">name</span><span class="p">);</span>
    <span class="n">uvm_object</span> <span class="n">obj</span><span class="p">;</span>
    <span class="n">uvm_factory</span> <span class="n">f</span> <span class="o">=</span> <span class="n">uvm_factory</span><span class="o">::</span><span class="n">get</span><span class="p">();</span>
    <span class="n">obj</span> <span class="o">=</span> <span class="n">f</span><span class="p">.</span><span class="n">create_object_by_type</span><span class="p">(</span><span class="n">get</span><span class="p">());</span>
    <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="p">$</span><span class="nb">cast</span><span class="p">(</span><span class="n">create</span><span class="p">,</span> <span class="n">obj</span><span class="p">))</span>
      <span class="n">uvm_report_fatal</span><span class="p">(</span><span class="s">"FCTTYP"</span><span class="p">,</span> <span class="s">"..."</span><span class="p">,</span> <span class="n">UVM_NONE</span><span class="p">);</span>
  <span class="k">endfunction</span>
<span class="k">endclass</span>
</code></pre></div></div>

<p>The registry classes are implemented as singletons; this means that there can only ever be a single instance of a certain registry and the <code class="language-plaintext highlighter-rouge">get(...)</code> function will return it. The object returned by the factory needs to be cast to make sure that it’s compatible with the original class. This means it has to be of either the same type or a sub-class.</p>

<p>Now that we know a little more about how the factory mechanism is implemented, we can get back to the problem at hand: associating abstract classes with registry classes.</p>

<p>A cool feature that <em>C++</em> has is template specialization. This means that it’s possible to modify the implementation of the code that gets generated when a template is specialized with a certain type. For our example, this would mean that we would writing something like:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">class</span> <span class="n">uvm_component_registry</span> <span class="p">#(</span><span class="n">some_abstract_class</span><span class="p">,</span> <span class="p">...)</span> <span class="k">extends</span>
  <span class="n">uvm_object_wrapper</span><span class="p">;</span>

  <span class="c1">// After elaboration with 'some_abstract_class' as an parameter</span>
  <span class="kt">virtual</span> <span class="k">function</span> <span class="n">uvm_component</span> <span class="n">create_component</span> <span class="p">(</span><span class="kt">string</span> <span class="n">name</span><span class="p">,</span>
                                                   <span class="n">uvm_component</span> <span class="n">parent</span><span class="p">);</span>
    <span class="cp">`uvm_fatal</span><span class="p">(</span><span class="s">"NEWERR"</span><span class="p">,</span> <span class="s">"Trying to create a virtual class"</span><span class="p">)</span>
    <span class="k">return</span> <span class="k">null</span><span class="p">;</span>
  <span class="k">endfunction</span>
<span class="k">endclass</span>
</code></pre></div></div>

<p>This means that for all other classes except <code class="language-plaintext highlighter-rouge">some_abstract_class</code> the <code class="language-plaintext highlighter-rouge">create_component(...)</code> function does exactly what it used to do in the generic implementation (i.e. it instantiates an object). For <code class="language-plaintext highlighter-rouge">some_abstract_class</code> it issues a fatal error instead, because this means that the user forgot something (most likely a factory override). This mechanism isn’t supported by <em>SystemVerilog</em>, so we’ll have to find another solution.</p>

<p>If we go back to the macro expansion, we can see that we can replace the type of <code class="language-plaintext highlighter-rouge">type_id</code> with something other than <code class="language-plaintext highlighter-rouge">uvm_component_registry</code>. We need a different class that extends <code class="language-plaintext highlighter-rouge">uvm_object_wrapper</code>, but doesn’t call the constructor of the class it’s parameterized with and instead issues a fatal error:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">class</span> <span class="n">vgm_abstract_component_registry</span> <span class="p">#(</span><span class="k">type</span> <span class="n">T</span><span class="o">=</span><span class="n">uvm_component</span><span class="p">,</span>
  <span class="kt">string</span> <span class="n">Tname</span><span class="o">=</span><span class="s">"&lt;unknown&gt;"</span><span class="p">)</span> <span class="k">extends</span> <span class="n">uvm_object_wrapper</span><span class="p">;</span>

  <span class="kt">virtual</span> <span class="k">function</span> <span class="n">uvm_component</span> <span class="n">create_component</span><span class="p">(</span><span class="kt">string</span> <span class="n">name</span><span class="p">,</span>
    <span class="n">uvm_component</span> <span class="n">parent</span>
  <span class="p">);</span>
    <span class="cp">`uvm_fatal</span><span class="p">(</span><span class="s">"INTERR"</span><span class="p">,</span> <span class="p">$</span><span class="nb">sformatf</span><span class="p">(</span><span class="s">"Trying to create an instance of class %s"</span><span class="p">,</span>
      <span class="n">Tname</span><span class="p">))</span>
    <span class="k">return</span> <span class="k">null</span><span class="p">;</span>
  <span class="k">endfunction</span>

  <span class="c1">// ...</span>
<span class="k">endclass</span>
</code></pre></div></div>

<p>We also need to implement the singleton infrastructure required to get an instance of the class:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">class</span> <span class="n">vgm_abstract_component_registry</span> <span class="p">#(</span><span class="k">type</span> <span class="n">T</span><span class="o">=</span><span class="n">uvm_component</span><span class="p">,</span>
  <span class="kt">string</span> <span class="n">Tname</span><span class="o">=</span><span class="s">"&lt;unknown&gt;"</span><span class="p">)</span> <span class="k">extends</span> <span class="n">uvm_object_wrapper</span><span class="p">;</span>

  <span class="k">typedef</span> <span class="n">vgm_abstract_component_registry</span> <span class="p">#(</span><span class="n">T</span><span class="p">,</span> <span class="n">Tname</span><span class="p">)</span> <span class="n">this_type</span><span class="p">;</span>

  <span class="k">local</span> <span class="kt">static</span> <span class="n">this_type</span> <span class="n">me</span> <span class="o">=</span> <span class="n">get</span><span class="p">();</span>

  <span class="kt">static</span> <span class="k">function</span> <span class="n">this_type</span> <span class="n">get</span><span class="p">();</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">me</span> <span class="o">==</span> <span class="k">null</span><span class="p">)</span> <span class="k">begin</span>
      <span class="n">uvm_factory</span> <span class="n">f</span> <span class="o">=</span> <span class="n">uvm_factory</span><span class="o">::</span><span class="n">get</span><span class="p">();</span>
      <span class="n">me</span> <span class="o">=</span> <span class="k">new</span><span class="p">();</span>
      <span class="n">f</span><span class="p">.</span><span class="n">register</span><span class="p">(</span><span class="n">me</span><span class="p">);</span>
    <span class="k">end</span>
    <span class="k">return</span> <span class="n">me</span><span class="p">;</span>
  <span class="k">endfunction</span>

  <span class="c1">// ...</span>
<span class="k">endclass</span>
</code></pre></div></div>

<p>The key part of the whole mechanism, the <code class="language-plaintext highlighter-rouge">create(...)</code> function is still missing. Notice that we’ve extended our class from <code class="language-plaintext highlighter-rouge">uvm_object_wrapper</code> directly. What I first tried was to extend <code class="language-plaintext highlighter-rouge">uvm_component_registry</code>, so I would only need to override the methods of interest and inherit the rest from the base class. This didn’t work, because that would mean elaborating the base class with a virtual class as its parameter, which results in an instant compile error. Even if the latter doesn’t happen, since the <code class="language-plaintext highlighter-rouge">create(...)</code> function of <code class="language-plaintext highlighter-rouge">uvm_component_registry</code> calls the class’s <code class="language-plaintext highlighter-rouge">get()</code> function (which is <strong>static</strong>) it won’t ever be possible to get it to call the <code class="language-plaintext highlighter-rouge">get()</code> function defined in the sub-class. This means that the factory would always receive an instance of <code class="language-plaintext highlighter-rouge">uvm_component_registry</code>.</p>

<p>What we need to do is (gasp!) duplicate the code that implements <code class="language-plaintext highlighter-rouge">create(...)</code> and <code class="language-plaintext highlighter-rouge">set_*_override(...)</code>, to allow users to use the new registry class in the same way as the original one from UVM:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">class</span> <span class="n">vgm_abstract_component_registry</span> <span class="p">#(</span><span class="k">type</span> <span class="n">T</span><span class="o">=</span><span class="n">uvm_component</span><span class="p">,</span>
  <span class="c1">// ...</span>

  <span class="kt">static</span> <span class="k">function</span> <span class="n">T</span> <span class="n">create</span><span class="p">(</span><span class="kt">string</span> <span class="n">name</span><span class="p">,</span> <span class="n">uvm_component</span> <span class="n">parent</span><span class="p">,</span> <span class="kt">string</span> <span class="n">contxt</span><span class="o">=</span><span class="s">""</span><span class="p">);</span>
    <span class="c1">// ...</span>
  <span class="k">endfunction</span>


  <span class="kt">static</span> <span class="k">function</span> <span class="kt">void</span> <span class="n">set_type_override</span> <span class="p">(</span><span class="n">uvm_object_wrapper</span> <span class="n">override_type</span><span class="p">,</span>
                                          <span class="kt">bit</span> <span class="n">replace</span><span class="o">=</span><span class="mi">1</span><span class="p">);</span>
    <span class="c1">// ...</span>
  <span class="k">endfunction</span>


  <span class="kt">static</span> <span class="k">function</span> <span class="kt">void</span> <span class="n">set_inst_override</span><span class="p">(</span><span class="n">uvm_object_wrapper</span> <span class="n">override_type</span><span class="p">,</span>
                                         <span class="kt">string</span> <span class="n">inst_path</span><span class="p">,</span>
                                         <span class="n">uvm_component</span> <span class="n">parent</span><span class="o">=</span><span class="k">null</span><span class="p">);</span>
    <span class="c1">// ...</span>
  <span class="k">endfunction</span>
<span class="k">endclass</span>
</code></pre></div></div>

<p>A lot of this clipboard based inheritance could have been avoided with some better choice of class hierarchy. Even the <code class="language-plaintext highlighter-rouge">uvm_object_registry</code> and <code class="language-plaintext highlighter-rouge">uvm_component_registry</code> classes contain a lot of duplicated code that could have been refactored. For example, a <code class="language-plaintext highlighter-rouge">uvm_registry</code> base class could have provided the required infrastructure for creation and factory overrides.</p>

<p>Aside from registering a class with the factory, we’ve seen that the <code class="language-plaintext highlighter-rouge">uvm_*_utils</code> macros do a bit more, like implementing the <code class="language-plaintext highlighter-rouge">get_type_name()</code> function. To have a similar look and feel to the UVM macros, we could define their abstract counterparts:</p>

<div class="language-verilog highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">`define</span> <span class="n">vgm_abstract_component_utils</span><span class="p">(</span><span class="n">T</span><span class="p">)</span> \
   <span class="cp">`m_vgm_abstract_component_registry_internal</span><span class="p">(</span><span class="n">T</span><span class="p">,</span><span class="n">T</span><span class="p">)</span> \
   <span class="cp">`m_uvm_get_type_name_func</span><span class="p">(</span><span class="n">T</span><span class="p">)</span>

<span class="cp">`define</span> m_vgm_abstract_component_registry_internal<span class="err">(</span>T<span class="err">,</span>S<span class="err">)</span> \
   typedef vgm_abstract_component_registry <span class="err">#(</span>T<span class="err">,`"</span>S<span class="err">`")</span> type_id<span class="p">;</span> \
   static function type_id get_type<span class="err">()</span><span class="p">;</span> \
     return type_id<span class="err">::</span>get<span class="err">()</span><span class="p">;</span> \
   endfunction \
   virtual function uvm_object_wrapper get_object_type<span class="err">()</span><span class="p">;</span> \
     return type_id<span class="err">::</span>get<span class="err">()</span><span class="p">;</span> \
   endfunction<span class="cp">
</span></code></pre></div></div>

<p>I’ve only shown the <code class="language-plaintext highlighter-rouge">abstract_component_utils</code> macro, but we can extend the concept to the <code class="language-plaintext highlighter-rouge">abstract_object_utils</code> macro, their <code class="language-plaintext highlighter-rouge">begin/end</code> variants and the <code class="language-plaintext highlighter-rouge">param</code> versions. I know we’re not supposed to be using the <code class="language-plaintext highlighter-rouge">m_uvm_*</code> versions of the macros, but I like to live on the wild side. For code that is supposed to enhance the library, I guess it’s not a big problem if it’s tightly coupled to its implementation.</p>

<p>If you find yourself in need of registering an abstract class with the factory, you can download the full code from <a href="https://github.com/tudortimi/vgm_abstract_registry">GitHub</a>.</p>]]></content><author><name>Tudor Timi</name></author><category term="SystemVerilog" /><category term="UVM" /><summary type="html"><![CDATA[Every now and again I stumble upon a situation where it’s natural to use an abstract class. A typical example is when working with parameterized classes and wanting to swap parameterizations:]]></summary></entry></feed>