Skip to content

Commit 97ba97a

Browse files
committed
Added blog on VHDL configurations.
1 parent c756476 commit 97ba97a

30 files changed

+1204
-35
lines changed
Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
:tags: VUnit, OSVVM, configurations
2+
:author: lasplund
3+
:excerpt: 1
4+
5+
Improved Support for VHDL Configurations and OSVVM
6+
==================================================
7+
8+
For quite some time, several initiatives have been underway to improve the integration between VUnit and OSVVM. Examples
9+
of these efforts are the `external logging framework integration feature
10+
<https://vunit.github.io/logging/user_guide.html#external-logging-framework-integration>`__ and the OSVVM pull request
11+
`#81 <https://github.com/OSVVM/OSVVM/pull/81>`__.
12+
13+
Another example is the introduction of support for top-level VHDL configurations which serves several purposes, for
14+
example:
15+
16+
1. Enabling the selection of the Device Under Test (DUT) to be used in a VUnit testbench.
17+
2. Direct support for running conventional OSVVM testbenches within the VUnit framework.
18+
19+
In this blog, we will primarily focus on top-level configurations but before delving into the specifics of these use cases, we will describe how VUnit addressed these issues in the past.
20+
21+
Selecting DUT Using Generics
22+
----------------------------
23+
24+
Sometimes the VHDL DUT comes in different variants (architectures) and there is a need to verify all of these with the
25+
same testbench. It could be an FPGA and an ASIC implementation or an RTL and a behavioral architecture. Before
26+
supporting VHDL configurations, VUnit addressed this issue with a combination of generics and an if-generate statement
27+
as showed in the example below. For the purpose of this blog, we have removed the complexities typically found in
28+
real-world designs and chosen to focus on the fundamental principles. Thus, we will use a simple variable-width
29+
flip-flop as the DUT for our demonstrations.
30+
31+
.. raw:: html
32+
:file: img/vhdl_configuration/selecting_dut_with_generics.html
33+
34+
This approach is straightforward: simply copy and paste the flip-flop instantiation, but modify the architecture to use
35+
based on the ``dut_arch`` generic. While the approach is simple it also introduces code duplication which can be a bit
36+
dangerous. In this case, since the copies are placed adjacent to each other, the risk of inadvertently changing one
37+
without updating the other is somewhat mitigated.
38+
39+
If your DUT has numerous ports, you can consider leveraging the VHDL-2019 interface construct as a means to raise the
40+
level of abstraction and reduce code duplication. This approach allows for a more concise representation of the design,
41+
provided your simulator supports the latest VHDL standard.
42+
43+
.. NOTE::
44+
There is a proposed update to the VHDL standard related to this topic as it would fully remove the code duplication.
45+
`Issue #235 <https://gitlab.com/IEEE-P1076/VHDL-Issues/-/issues/235>`__ proposes that a string should be possible
46+
to use when specifying the architecture in an entity instantiation, i.e. ``"rtl"`` or ``"behavioral"`` rather than
47+
``rtl`` or ``behavioral``. In our example we would simply have a single entity instantiation which architecture is
48+
specified with the ``dut_arch`` generic.
49+
50+
The various settings of the ``dut_arch`` generic are handled with a VUnit configuration in the Python run script.
51+
Initially, the use of both VUnit and VHDL configuration concepts may appear confusing, but we will soon see that a VHDL
52+
configuration is a special case of the broader VUnit configuration concept. In this example, we are also testing the DUT
53+
with multiple ``width`` settings. Note how we can use the ``product`` function from ``itertools`` to iterate over all
54+
combinations of ``dut_arch`` and ``width``. This is equivalent to two nested loops over these generics but scales better
55+
as the number of generics to combine increases.
56+
57+
.. raw:: html
58+
:file: img/vhdl_configuration/create_vunit_configuration_for_selecting_dut.html
59+
60+
If we list all the tests, we will see that there are four for each test
61+
case in the testbench, one for each combination of ``dut_arch`` and ``width``:
62+
63+
.. raw:: html
64+
:file: img/vhdl_configuration/tb_selecting_dut_with_generics_stdout.html
65+
66+
Selecting DUT Using VHDL Configurations
67+
---------------------------------------
68+
69+
When using VHDL configurations we need three ingredients in our testbench
70+
71+
1. A component declaration for the DUT. In the example below it has been
72+
placed in the declarative part of the testbench architecture but it
73+
can also be placed in a separate package.
74+
2. A component instantiation of the declared component. Note that the
75+
``component`` keyword is optional and can be excluded.
76+
3. A configuration declaration for each DUT architecture
77+
78+
.. raw:: html
79+
:file: img/vhdl_configuration/selecting_dut_with_vhdl_configuration.html
80+
81+
Instead of assigning a generic to select our architecture, we now specify which VHDL configuration our VUnit configuration should use:
82+
83+
.. raw:: html
84+
:file: img/vhdl_configuration/create_vunit_configuration_for_selecting_dut_with_a_vhdl_configuration.html
85+
86+
Incorporating VHDL configurations within VUnit configurations brings forth another advantage. From a VHDL point of view,
87+
VHDL configurations are linked to entities, such as the testbench entity in our scenario. However, a VUnit configuration
88+
can also be applied to specific test cases, opening up the possibility of using VHDL configurations at that finer level
89+
of granularity. For instance, consider a situation where we have an FPGA and an ASIC implementation/architecure that
90+
differ only in the memory IPs they use. In such a case, it might be sufficient to simulate only one of the architectures
91+
for the test cases not involving memory operations.
92+
93+
To illustrate this using the flip-flop example, let's create a test where we set ``width`` to 32 and exclusively
94+
simulate it using the RTL architecture:
95+
96+
.. raw:: html
97+
:file: img/vhdl_configuration/vhdl_configuration_on_a_test_case.html
98+
99+
Now, we have an additional entry in our list of tests:
100+
101+
.. raw:: html
102+
:file: img/vhdl_configuration/tb_selecting_dut_with_vhdl_configuration_stdout.html
103+
104+
Choosing between VHDL configurations and generics is primarily a matter of personal preference. The generic approach led
105+
us to multiple direct entity instantiations and code duplication. However, the configuration approach demands a
106+
component declaration, which essentially duplicates the DUT entity declaration. Additionally, VHDL configuration
107+
declarations are also necessary.
108+
109+
Selecting Test Runner Using VHDL Configurations
110+
-----------------------------------------------
111+
112+
In the previous examples, the VUnit test cases were located in a process called ``test_runner`` residing alongside the
113+
DUT. This is the most straightforward arrangement, as it provides the test cases with direct access to the DUT's
114+
interface. An alternative approach involves encapsulating ``test_runner`` within an entity, which is subsequently
115+
instantiated within the testbench. Such a ``test_runner`` entity needs access to the ``runner_cfg`` and ``width``
116+
generics, in addition to the ``clk_period`` constant and the interface ports of the DUT.
117+
118+
.. raw:: html
119+
:file: img/vhdl_configuration/test_runner_entity.html
120+
121+
Note that the runner configuration generic is called ``nested_runner_cfg`` and not ``runner_cfg``. The reason is that
122+
``runner_cfg`` is the signature used to identify a testbench, the top-level of a simulation. The ``test_runner`` entity
123+
is not a simulation top-level and must not be mistaken as such.
124+
125+
We can now replace the testbench ``test_runner`` process and watchdog with an instantiation of this component:
126+
127+
.. raw:: html
128+
:file: img/vhdl_configuration/test_runner_component_instantiation.html
129+
130+
Having relocated ``test_runner`` into an entity, we can have VHDL configurations selecting which test runner to use, and
131+
let each such test runner represent a single test. This setup is the conventional methodology seen in OSVVM
132+
testbenches. With VUnit's extended support for VHDL configurations, it becomes possible to keep that structure when
133+
adding VUnit capabilities. For example, this is the architecture for the reset test:
134+
135+
.. raw:: html
136+
:file: img/vhdl_configuration/test_reset_architecture_of_test_runner.html
137+
138+
.. NOTE::
139+
When using several configurations to select what test runner to use, each test runner can only contain a single test, i.e. no test cases specified by the use of the ``run`` function are allowed.
140+
141+
Below are the two configurations that select this particular test along with one of the ``rtl`` and ``behavioral``
142+
architectures for the DUT:
143+
144+
.. raw:: html
145+
:file: img/vhdl_configuration/test_reset_configurations.html
146+
147+
This example highlights a drawback of VHDL configurations: every combination of architectures to use in a test has to be
148+
manually created. When we use generics and if generate statements to select architectures, we create all combinations
149+
**programatically** in the Python script using the ``itertools.product`` function. Despite this, Python can continue to
150+
play a role in alleviating certain aspects of the combinatorial workload:
151+
152+
.. raw:: html
153+
:file: img/vhdl_configuration/create_vunit_configuration_for_selecting_dut_and_runner_with_a_vhdl_configuration.html
154+
155+
.. raw:: html
156+
:file: img/vhdl_configuration/tb_selecting_test_runner_with_vhdl_configuration_stdout.html
157+
158+
That concludes our discussion for now. As always, we highly value your feedback and appreciate any insights you might have to offer.
159+
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<div class="highlight"><pre><span></span><span class="n">tb</span> <span class="o">=</span> <span class="n">lib</span><span class="o">.</span><span class="n">test_bench</span><span class="p">(</span><span class="s2">&quot;tb_selecting_dut_with_generics&quot;</span><span class="p">)</span>
2+
3+
<span class="k">for</span> <span class="n">dut_arch</span><span class="p">,</span> <span class="n">width</span> <span class="ow">in</span> <span class="n">itertools</span><span class="o">.</span><span class="n">product</span><span class="p">([</span><span class="s2">&quot;rtl&quot;</span><span class="p">,</span> <span class="s2">&quot;behavioral&quot;</span><span class="p">],</span> <span class="p">[</span><span class="mi">8</span><span class="p">,</span> <span class="mi">16</span><span class="p">]):</span>
4+
<span class="n">tb</span><span class="o">.</span><span class="n">add_config</span><span class="p">(</span>
5+
<span class="n">name</span><span class="o">=</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">dut_arch</span><span class="si">}</span><span class="s2">_</span><span class="si">{</span><span class="n">width</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">,</span>
6+
<span class="n">generics</span><span class="o">=</span><span class="nb">dict</span><span class="p">(</span><span class="n">width</span><span class="o">=</span><span class="n">width</span><span class="p">,</span> <span class="n">dff_arch</span><span class="o">=</span><span class="n">dut_arch</span><span class="p">),</span>
7+
<span class="p">)</span>
8+
</pre></div>
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<div class="highlight"><pre><span></span><span class="n">tb</span> <span class="o">=</span> <span class="n">lib</span><span class="o">.</span><span class="n">test_bench</span><span class="p">(</span><span class="s2">&quot;tb_selecting_test_runner_with_vhdl_configuration&quot;</span><span class="p">)</span>
2+
3+
<span class="k">for</span> <span class="n">dut_arch</span><span class="p">,</span> <span class="n">width</span><span class="p">,</span> <span class="n">test_case_name</span> <span class="ow">in</span> <span class="n">itertools</span><span class="o">.</span><span class="n">product</span><span class="p">(</span>
4+
<span class="p">[</span><span class="s2">&quot;rtl&quot;</span><span class="p">,</span> <span class="s2">&quot;behavioral&quot;</span><span class="p">],</span> <span class="p">[</span><span class="mi">8</span><span class="p">,</span> <span class="mi">16</span><span class="p">],</span> <span class="p">[</span><span class="s2">&quot;test_reset&quot;</span><span class="p">,</span> <span class="s2">&quot;test_state_change&quot;</span><span class="p">]</span>
5+
<span class="p">):</span>
6+
<span class="n">vhdl_configuration_name</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">test_case_name</span><span class="si">}</span><span class="s2">_</span><span class="si">{</span><span class="n">dut_arch</span><span class="si">}</span><span class="s2">&quot;</span>
7+
<span class="n">tb</span><span class="o">.</span><span class="n">add_config</span><span class="p">(</span>
8+
<span class="n">name</span><span class="o">=</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">vhdl_configuration_name</span><span class="si">}</span><span class="s2">_</span><span class="si">{</span><span class="n">width</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">,</span>
9+
<span class="n">generics</span><span class="o">=</span><span class="nb">dict</span><span class="p">(</span><span class="n">width</span><span class="o">=</span><span class="n">width</span><span class="p">),</span>
10+
<span class="n">vhdl_configuration_name</span><span class="o">=</span><span class="n">vhdl_configuration_name</span><span class="p">,</span>
11+
<span class="p">)</span>
12+
</pre></div>
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<div class="highlight"><pre><span></span><span class="n">tb</span> <span class="o">=</span> <span class="n">lib</span><span class="o">.</span><span class="n">test_bench</span><span class="p">(</span><span class="s2">&quot;tb_selecting_dut_with_vhdl_configuration&quot;</span><span class="p">)</span>
2+
3+
<span class="k">for</span> <span class="n">dut_arch</span><span class="p">,</span> <span class="n">width</span> <span class="ow">in</span> <span class="n">itertools</span><span class="o">.</span><span class="n">product</span><span class="p">([</span><span class="s2">&quot;rtl&quot;</span><span class="p">,</span> <span class="s2">&quot;behavioral&quot;</span><span class="p">],</span> <span class="p">[</span><span class="mi">8</span><span class="p">,</span> <span class="mi">16</span><span class="p">]):</span>
4+
<span class="n">tb</span><span class="o">.</span><span class="n">add_config</span><span class="p">(</span>
5+
<span class="n">name</span><span class="o">=</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">dut_arch</span><span class="si">}</span><span class="s2">_</span><span class="si">{</span><span class="n">width</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">,</span>
6+
<span class="n">generics</span><span class="o">=</span><span class="nb">dict</span><span class="p">(</span><span class="n">width</span><span class="o">=</span><span class="n">width</span><span class="p">),</span>
7+
<span class="n">vhdl_configuration_name</span><span class="o">=</span><span class="n">dut_arch</span><span class="p">,</span>
8+
<span class="p">)</span>
9+
</pre></div>

0 commit comments

Comments
 (0)