|
| 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 | + |
0 commit comments