diff --git a/docs/blog/2023_08_26_vhdl_configurations.rst b/docs/blog/2023_08_26_vhdl_configurations.rst new file mode 100644 index 000000000..f9b9863a8 --- /dev/null +++ b/docs/blog/2023_08_26_vhdl_configurations.rst @@ -0,0 +1,159 @@ +:tags: VUnit, OSVVM, configurations +:author: lasplund +:excerpt: 1 + +Improved Support for VHDL Configurations and OSVVM +================================================== + +For quite some time, several initiatives have been underway to improve the integration between VUnit and OSVVM. Examples +of these efforts are the `external logging framework integration feature +`__ and the OSVVM pull request +`#81 `__. + +Another example is the introduction of support for top-level VHDL configurations which serves several purposes, for +example: + +1. Enabling the selection of the Device Under Test (DUT) to be used in a VUnit testbench. +2. Direct support for running conventional OSVVM testbenches within the VUnit framework. + +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. + +Selecting DUT Using Generics +---------------------------- + +Sometimes the VHDL DUT comes in different variants (architectures) and there is a need to verify all of these with the +same testbench. It could be an FPGA and an ASIC implementation or an RTL and a behavioral architecture. Before +supporting VHDL configurations, VUnit addressed this issue with a combination of generics and an if-generate statement +as showed in the example below. For the purpose of this blog, we have removed the complexities typically found in +real-world designs and chosen to focus on the fundamental principles. Thus, we will use a simple variable-width +flip-flop as the DUT for our demonstrations. + +.. raw:: html + :file: img/vhdl_configuration/selecting_dut_with_generics.html + +This approach is straightforward: simply copy and paste the flip-flop instantiation, but modify the architecture to use +based on the ``dut_arch`` generic. While the approach is simple it also introduces code duplication which can be a bit +dangerous. In this case, since the copies are placed adjacent to each other, the risk of inadvertently changing one +without updating the other is somewhat mitigated. + +If your DUT has numerous ports, you can consider leveraging the VHDL-2019 interface construct as a means to raise the +level of abstraction and reduce code duplication. This approach allows for a more concise representation of the design, +provided your simulator supports the latest VHDL standard. + +.. NOTE:: + There is a proposed update to the VHDL standard related to this topic as it would fully remove the code duplication. + `Issue #235 `__ proposes that a string should be possible + to use when specifying the architecture in an entity instantiation, i.e. ``"rtl"`` or ``"behavioral"`` rather than + ``rtl`` or ``behavioral``. In our example we would simply have a single entity instantiation which architecture is + specified with the ``dut_arch`` generic. + +The various settings of the ``dut_arch`` generic are handled with a VUnit configuration in the Python run script. +Initially, the use of both VUnit and VHDL configuration concepts may appear confusing, but we will soon see that a VHDL +configuration is a special case of the broader VUnit configuration concept. In this example, we are also testing the DUT +with multiple ``width`` settings. Note how we can use the ``product`` function from ``itertools`` to iterate over all +combinations of ``dut_arch`` and ``width``. This is equivalent to two nested loops over these generics but scales better +as the number of generics to combine increases. + +.. raw:: html + :file: img/vhdl_configuration/create_vunit_configuration_for_selecting_dut.html + +If we list all the tests, we will see that there are four for each test +case in the testbench, one for each combination of ``dut_arch`` and ``width``: + +.. raw:: html + :file: img/vhdl_configuration/tb_selecting_dut_with_generics_stdout.html + +Selecting DUT Using VHDL Configurations +--------------------------------------- + +When using VHDL configurations we need three ingredients in our testbench + +1. A component declaration for the DUT. In the example below it has been + placed in the declarative part of the testbench architecture but it + can also be placed in a separate package. +2. A component instantiation of the declared component. Note that the + ``component`` keyword is optional and can be excluded. +3. A configuration declaration for each DUT architecture + +.. raw:: html + :file: img/vhdl_configuration/selecting_dut_with_vhdl_configuration.html + +Instead of assigning a generic to select our architecture, we now specify which VHDL configuration our VUnit configuration should use: + +.. raw:: html + :file: img/vhdl_configuration/create_vunit_configuration_for_selecting_dut_with_a_vhdl_configuration.html + +Incorporating VHDL configurations within VUnit configurations brings forth another advantage. From a VHDL point of view, +VHDL configurations are linked to entities, such as the testbench entity in our scenario. However, a VUnit configuration +can also be applied to specific test cases, opening up the possibility of using VHDL configurations at that finer level +of granularity. For instance, consider a situation where we have an FPGA and an ASIC implementation/architecure that +differ only in the memory IPs they use. In such a case, it might be sufficient to simulate only one of the architectures +for the test cases not involving memory operations. + +To illustrate this using the flip-flop example, let's create a test where we set ``width`` to 32 and exclusively +simulate it using the RTL architecture: + +.. raw:: html + :file: img/vhdl_configuration/vhdl_configuration_on_a_test_case.html + +Now, we have an additional entry in our list of tests: + +.. raw:: html + :file: img/vhdl_configuration/tb_selecting_dut_with_vhdl_configuration_stdout.html + +Choosing between VHDL configurations and generics is primarily a matter of personal preference. The generic approach led +us to multiple direct entity instantiations and code duplication. However, the configuration approach demands a +component declaration, which essentially duplicates the DUT entity declaration. Additionally, VHDL configuration +declarations are also necessary. + +Selecting Test Runner Using VHDL Configurations +----------------------------------------------- + +In the previous examples, the VUnit test cases were located in a process called ``test_runner`` residing alongside the +DUT. This is the most straightforward arrangement, as it provides the test cases with direct access to the DUT's +interface. An alternative approach involves encapsulating ``test_runner`` within an entity, which is subsequently +instantiated within the testbench. Such a ``test_runner`` entity needs access to the ``runner_cfg`` and ``width`` +generics, in addition to the ``clk_period`` constant and the interface ports of the DUT. + +.. raw:: html + :file: img/vhdl_configuration/test_runner_entity.html + +Note that the runner configuration generic is called ``nested_runner_cfg`` and not ``runner_cfg``. The reason is that +``runner_cfg`` is the signature used to identify a testbench, the top-level of a simulation. The ``test_runner`` entity +is not a simulation top-level and must not be mistaken as such. + +We can now replace the testbench ``test_runner`` process and watchdog with an instantiation of this component: + +.. raw:: html + :file: img/vhdl_configuration/test_runner_component_instantiation.html + +Having relocated ``test_runner`` into an entity, we can have VHDL configurations selecting which test runner to use, and +let each such test runner represent a single test. This setup is the conventional methodology seen in OSVVM +testbenches. With VUnit's extended support for VHDL configurations, it becomes possible to keep that structure when +adding VUnit capabilities. For example, this is the architecture for the reset test: + +.. raw:: html + :file: img/vhdl_configuration/test_reset_architecture_of_test_runner.html + +.. NOTE:: + 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. + +Below are the two configurations that select this particular test along with one of the ``rtl`` and ``behavioral`` +architectures for the DUT: + +.. raw:: html + :file: img/vhdl_configuration/test_reset_configurations.html + +This example highlights a drawback of VHDL configurations: every combination of architectures to use in a test has to be +manually created. When we use generics and if generate statements to select architectures, we create all combinations +**programatically** in the Python script using the ``itertools.product`` function. Despite this, Python can continue to +play a role in alleviating certain aspects of the combinatorial workload: + +.. raw:: html + :file: img/vhdl_configuration/create_vunit_configuration_for_selecting_dut_and_runner_with_a_vhdl_configuration.html + +.. raw:: html + :file: img/vhdl_configuration/tb_selecting_test_runner_with_vhdl_configuration_stdout.html + +That concludes our discussion for now. As always, we highly value your feedback and appreciate any insights you might have to offer. + diff --git a/docs/blog/img/vhdl_configuration/create_vunit_configuration_for_selecting_dut.html b/docs/blog/img/vhdl_configuration/create_vunit_configuration_for_selecting_dut.html new file mode 100644 index 000000000..e427b3b16 --- /dev/null +++ b/docs/blog/img/vhdl_configuration/create_vunit_configuration_for_selecting_dut.html @@ -0,0 +1,8 @@ +
tb = lib.test_bench("tb_selecting_dut_with_generics")
+
+for dut_arch, width in itertools.product(["rtl", "behavioral"], [8, 16]):
+    tb.add_config(
+        name=f"{dut_arch}_{width}",
+        generics=dict(width=width, dff_arch=dut_arch),
+    )
+
diff --git a/docs/blog/img/vhdl_configuration/create_vunit_configuration_for_selecting_dut_and_runner_with_a_vhdl_configuration.html b/docs/blog/img/vhdl_configuration/create_vunit_configuration_for_selecting_dut_and_runner_with_a_vhdl_configuration.html new file mode 100644 index 000000000..13fda5cbc --- /dev/null +++ b/docs/blog/img/vhdl_configuration/create_vunit_configuration_for_selecting_dut_and_runner_with_a_vhdl_configuration.html @@ -0,0 +1,12 @@ +
tb = lib.test_bench("tb_selecting_test_runner_with_vhdl_configuration")
+
+for dut_arch, width, test_case_name in itertools.product(
+    ["rtl", "behavioral"], [8, 16], ["test_reset", "test_state_change"]
+):
+    vhdl_configuration_name = f"{test_case_name}_{dut_arch}"
+    tb.add_config(
+        name=f"{vhdl_configuration_name}_{width}",
+        generics=dict(width=width),
+        vhdl_configuration_name=vhdl_configuration_name,
+    )
+
diff --git a/docs/blog/img/vhdl_configuration/create_vunit_configuration_for_selecting_dut_with_a_vhdl_configuration.html b/docs/blog/img/vhdl_configuration/create_vunit_configuration_for_selecting_dut_with_a_vhdl_configuration.html new file mode 100644 index 000000000..697ebaf5c --- /dev/null +++ b/docs/blog/img/vhdl_configuration/create_vunit_configuration_for_selecting_dut_with_a_vhdl_configuration.html @@ -0,0 +1,9 @@ +
tb = lib.test_bench("tb_selecting_dut_with_vhdl_configuration")
+
+for dut_arch, width in itertools.product(["rtl", "behavioral"], [8, 16]):
+    tb.add_config(
+        name=f"{dut_arch}_{width}",
+        generics=dict(width=width),
+        vhdl_configuration_name=dut_arch,
+    )
+
diff --git a/docs/blog/img/vhdl_configuration/selecting_dut_with_generics.html b/docs/blog/img/vhdl_configuration/selecting_dut_with_generics.html new file mode 100644 index 000000000..7a651d94b --- /dev/null +++ b/docs/blog/img/vhdl_configuration/selecting_dut_with_generics.html @@ -0,0 +1,62 @@ +
entity tb_selecting_dut_with_generics is
+  generic(
+    runner_cfg : string;
+    width : positive;
+    dff_arch : string
+  );
+end entity;
+
+architecture tb of tb_selecting_dut_with_generics is
+  ...
+begin
+  test_runner : process
+  begin
+    test_runner_setup(runner, runner_cfg);
+
+    while test_suite loop
+      if run("Test reset") then
+        ...
+      elsif run("Test state change") then
+        ...
+      end if;
+    end loop;
+
+    test_runner_cleanup(runner);
+  end process;
+
+  test_runner_watchdog(runner, 10 * clk_period);
+
+  test_fixture : block is
+  begin
+    clk <= not clk after clk_period / 2;
+
+    dut_selection : if dff_arch = "rtl" generate
+      dut : entity work.dff(rtl)
+        generic map(
+          width => width
+        )
+        port map(
+          clk => clk,
+          reset => reset,
+          d => d,
+          q => q
+        );
+
+    elsif dff_arch = "behavioral" generate
+      dut : entity work.dff(behavioral)
+        generic map(
+          width => width
+        )
+        port map(
+          clk => clk,
+          reset => reset,
+          d => d,
+          q => q
+        );
+
+    else generate
+      error("Unknown DFF architecture");
+    end generate;
+  end block;
+end architecture;
+
diff --git a/docs/blog/img/vhdl_configuration/selecting_dut_with_vhdl_configuration.html b/docs/blog/img/vhdl_configuration/selecting_dut_with_vhdl_configuration.html new file mode 100644 index 000000000..d4a347bab --- /dev/null +++ b/docs/blog/img/vhdl_configuration/selecting_dut_with_vhdl_configuration.html @@ -0,0 +1,79 @@ +
entity tb_selecting_dut_with_vhdl_configuration is
+  generic(
+    runner_cfg : string;
+    width : positive
+  );
+end entity;
+
+architecture tb of tb_selecting_dut_with_vhdl_configuration is
+  ...
+
+  -- Component declaration
+  component dff is
+    generic(
+      width : positive := width
+    );
+    port(
+      clk : in std_logic;
+      reset : in std_logic;
+      d : in std_logic_vector(width - 1 downto 0);
+      q : out std_logic_vector(width - 1 downto 0)
+    );
+  end component;
+begin
+  test_runner : process
+  begin
+    test_runner_setup(runner, runner_cfg);
+
+    while test_suite loop
+      if run("Test reset") then
+        ...
+      elsif run("Test state change") then
+        ...
+      end if;
+    end loop;
+
+    test_runner_cleanup(runner);
+  end process;
+
+  test_runner_watchdog(runner, 10 * clk_period);
+
+  test_fixture : block is
+  begin
+    clk <= not clk after clk_period / 2;
+
+    -- Component instantiation
+    dut : component dff
+      generic map(
+        width => width
+      )
+      port map(
+        clk => clk,
+        reset => reset,
+        d => d,
+        q => q
+      );
+  end block;
+end architecture;
+
+-- Configuration declarations
+configuration rtl of tb_selecting_dut_with_vhdl_configuration is
+  for tb
+    for test_fixture
+      for dut : dff
+        use entity work.dff(rtl);
+      end for;
+    end for;
+  end for;
+end;
+
+configuration behavioral of tb_selecting_dut_with_vhdl_configuration is
+  for tb
+    for test_fixture
+      for dut : dff
+        use entity work.dff(behavioral);
+      end for;
+    end for;
+  end for;
+end;
+
diff --git a/docs/blog/img/vhdl_configuration/tb_selecting_dut_with_generics_stdout.html b/docs/blog/img/vhdl_configuration/tb_selecting_dut_with_generics_stdout.html new file mode 100644 index 000000000..68103bbe3 --- /dev/null +++ b/docs/blog/img/vhdl_configuration/tb_selecting_dut_with_generics_stdout.html @@ -0,0 +1,11 @@ +
> python run.py --list
+lib.tb_selecting_dut_with_generics.rtl_8.Test reset
+lib.tb_selecting_dut_with_generics.rtl_16.Test reset
+lib.tb_selecting_dut_with_generics.behavioral_8.Test reset
+lib.tb_selecting_dut_with_generics.behavioral_16.Test reset
+lib.tb_selecting_dut_with_generics.rtl_8.Test state change
+lib.tb_selecting_dut_with_generics.rtl_16.Test state change
+lib.tb_selecting_dut_with_generics.behavioral_8.Test state change
+lib.tb_selecting_dut_with_generics.behavioral_16.Test state change
+Listed 8 tests
+
diff --git a/docs/blog/img/vhdl_configuration/tb_selecting_dut_with_vhdl_configuration_stdout.html b/docs/blog/img/vhdl_configuration/tb_selecting_dut_with_vhdl_configuration_stdout.html new file mode 100644 index 000000000..39f9132ed --- /dev/null +++ b/docs/blog/img/vhdl_configuration/tb_selecting_dut_with_vhdl_configuration_stdout.html @@ -0,0 +1,12 @@ +
> python run.py --list
+lib.tb_selecting_dut_with_vhdl_configuration.rtl_8.Test reset
+lib.tb_selecting_dut_with_vhdl_configuration.rtl_16.Test reset
+lib.tb_selecting_dut_with_vhdl_configuration.behavioral_8.Test reset
+lib.tb_selecting_dut_with_vhdl_configuration.behavioral_16.Test reset
+lib.tb_selecting_dut_with_vhdl_configuration.rtl_32.Test reset
+lib.tb_selecting_dut_with_vhdl_configuration.rtl_8.Test state change
+lib.tb_selecting_dut_with_vhdl_configuration.rtl_16.Test state change
+lib.tb_selecting_dut_with_vhdl_configuration.behavioral_8.Test state change
+lib.tb_selecting_dut_with_vhdl_configuration.behavioral_16.Test state change
+Listed 9 tests
+
diff --git a/docs/blog/img/vhdl_configuration/tb_selecting_test_runner_with_vhdl_configuration_stdout.html b/docs/blog/img/vhdl_configuration/tb_selecting_test_runner_with_vhdl_configuration_stdout.html new file mode 100644 index 000000000..3d532dac0 --- /dev/null +++ b/docs/blog/img/vhdl_configuration/tb_selecting_test_runner_with_vhdl_configuration_stdout.html @@ -0,0 +1,11 @@ +
> python run.py --list
+lib.tb_selecting_test_runner_with_vhdl_configuration.test_reset_rtl_8
+lib.tb_selecting_test_runner_with_vhdl_configuration.test_state_change_rtl_8
+lib.tb_selecting_test_runner_with_vhdl_configuration.test_reset_rtl_16
+lib.tb_selecting_test_runner_with_vhdl_configuration.test_state_change_rtl_16
+lib.tb_selecting_test_runner_with_vhdl_configuration.test_reset_behavioral_8
+lib.tb_selecting_test_runner_with_vhdl_configuration.test_state_change_behavioral_8
+lib.tb_selecting_test_runner_with_vhdl_configuration.test_reset_behavioral_16
+lib.tb_selecting_test_runner_with_vhdl_configuration.test_state_change_behavioral_16
+Listed 8 tests
+
diff --git a/docs/blog/img/vhdl_configuration/test_reset_architecture_of_test_runner.html b/docs/blog/img/vhdl_configuration/test_reset_architecture_of_test_runner.html new file mode 100644 index 000000000..a93b5917b --- /dev/null +++ b/docs/blog/img/vhdl_configuration/test_reset_architecture_of_test_runner.html @@ -0,0 +1,14 @@ +
architecture test_reset_architecture of test_runner is
+begin
+  main : process
+  begin
+    test_runner_setup(runner, nested_runner_cfg);
+
+    -- Test code here
+
+    test_runner_cleanup(runner);
+  end process;
+
+  test_runner_watchdog(runner, 10 * clk_period);
+end;
+
diff --git a/docs/blog/img/vhdl_configuration/test_reset_configurations.html b/docs/blog/img/vhdl_configuration/test_reset_configurations.html new file mode 100644 index 000000000..0e09a35f5 --- /dev/null +++ b/docs/blog/img/vhdl_configuration/test_reset_configurations.html @@ -0,0 +1,28 @@ +
configuration test_reset_behavioral of tb_selecting_test_runner_with_vhdl_configuration is
+  for tb
+    for test_runner_inst : test_runner
+      use entity work.test_runner(test_reset_architecture);
+    end for;
+
+    for test_fixture
+      for dut : dff
+        use entity work.dff(behavioral);
+      end for;
+    end for;
+  end for;
+end;
+
+configuration test_reset_rtl of tb_selecting_test_runner_with_vhdl_configuration is
+  for tb
+    for test_runner_inst : test_runner
+      use entity work.test_runner(test_reset_architecture);
+    end for;
+
+    for test_fixture
+      for dut : dff
+        use entity work.dff(rtl);
+      end for;
+    end for;
+  end for;
+end;
+
diff --git a/docs/blog/img/vhdl_configuration/test_runner_component_instantiation.html b/docs/blog/img/vhdl_configuration/test_runner_component_instantiation.html new file mode 100644 index 000000000..39719d567 --- /dev/null +++ b/docs/blog/img/vhdl_configuration/test_runner_component_instantiation.html @@ -0,0 +1,13 @@ +
test_runner_inst : component test_runner
+  generic map(
+    clk_period => clk_period,
+    width => width,
+    nested_runner_cfg => runner_cfg
+  )
+  port map(
+    reset => reset,
+    clk => clk,
+    d => d,
+    q => q
+  );
+
diff --git a/docs/blog/img/vhdl_configuration/test_runner_entity.html b/docs/blog/img/vhdl_configuration/test_runner_entity.html new file mode 100644 index 000000000..9614bea32 --- /dev/null +++ b/docs/blog/img/vhdl_configuration/test_runner_entity.html @@ -0,0 +1,14 @@ +
entity test_runner is
+  generic(
+    clk_period : time;
+    width : positive;
+    nested_runner_cfg : string
+  );
+  port(
+    reset : out std_logic;
+    clk : in std_logic;
+    d : out std_logic_vector(width - 1 downto 0);
+    q : in std_logic_vector(width - 1 downto 0)
+  );
+end entity;
+
diff --git a/docs/blog/img/vhdl_configuration/vhdl_configuration_on_a_test_case.html b/docs/blog/img/vhdl_configuration/vhdl_configuration_on_a_test_case.html new file mode 100644 index 000000000..1649eacdb --- /dev/null +++ b/docs/blog/img/vhdl_configuration/vhdl_configuration_on_a_test_case.html @@ -0,0 +1,2 @@ +
tb.test("Test reset").add_config(name="rtl_32", generics=dict(width=32), vhdl_configuration_name="rtl")
+
diff --git a/docs/blog/src/vhdl_configuration/dff.vhd b/docs/blog/src/vhdl_configuration/dff.vhd new file mode 100644 index 000000000..acac60107 --- /dev/null +++ b/docs/blog/src/vhdl_configuration/dff.vhd @@ -0,0 +1,43 @@ +-- This Source Code Form is subject to the terms of the Mozilla Public +-- License, v. 2.0. If a copy of the MPL was not distributed with this file, +-- You can obtain one at http://mozilla.org/MPL/2.0/. +-- +-- Copyright (c) 2014-2023, Lars Asplund lars.anders.asplund@gmail.com +library ieee; +use ieee.std_logic_1164.all; + +entity dff is + generic( + width : positive := 8 + ); + port( + clk : in std_logic; + reset : in std_logic; + d : in std_logic_vector(width - 1 downto 0); + q : out std_logic_vector(width - 1 downto 0) + ); +end; + +architecture rtl of dff is +begin + process(clk) is + begin + if rising_edge(clk) then + if reset = '1' then + q <= (others => '0'); + else + q <= d; + end if; + end if; + end process; +end; + +architecture behavioral of dff is +begin + process + begin + wait until rising_edge(clk); + q <= (others => '0') when reset else d; + end process; +end; + diff --git a/docs/blog/src/vhdl_configuration/run.py b/docs/blog/src/vhdl_configuration/run.py new file mode 100644 index 000000000..d2a4fc9f9 --- /dev/null +++ b/docs/blog/src/vhdl_configuration/run.py @@ -0,0 +1,170 @@ +#!/usr/bin/env python3 + +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this file, +# You can obtain one at http://mozilla.org/MPL/2.0/. +# +# Copyright (c) 2014-2023, Lars Asplund lars.anders.asplund@gmail.com + +import sys +import itertools +from os import walk +from pathlib import Path +from io import StringIO +from vunit import VUnit, VUnitCLI +from tools.doc_support import highlight_code, highlight_log, LogRegistry + +cli = VUnitCLI() +args = cli.parse_args() +root = Path(__file__).parent + + +def extract_snippets(): + for snippet in [ + "selecting_dut_with_generics", + ]: + highlight_code( + root / "tb_selecting_dut_with_generics.vhd", + root / ".." / ".." / "img" / "vhdl_configuration" / f"{snippet}.html", + snippet, + ) + + for snippet in [ + "create_vunit_configuration_for_selecting_dut", + "create_vunit_configuration_for_selecting_dut_with_a_vhdl_configuration", + "vhdl_configuration_on_a_test_case", + "create_vunit_configuration_for_selecting_dut_and_runner_with_a_vhdl_configuration", + ]: + highlight_code( + root / "run.py", + root / ".." / ".." / "img" / "vhdl_configuration" / f"{snippet}.html", + snippet, + language="python", + ) + + for snippet in [ + "selecting_dut_with_vhdl_configuration", + ]: + highlight_code( + root / "tb_selecting_dut_with_vhdl_configuration.vhd", + root / ".." / ".." / "img" / "vhdl_configuration" / f"{snippet}.html", + snippet, + ) + + for snippet in [ + "test_runner_component_instantiation", + ]: + highlight_code( + root / "tb_selecting_test_runner_with_vhdl_configuration.vhd", + root / ".." / ".." / "img" / "vhdl_configuration" / f"{snippet}.html", + snippet, + ) + + for snippet in ["test_reset_architecture_of_test_runner", "test_reset_configurations"]: + highlight_code( + root / "test_reset.vhd", + root / ".." / ".." / "img" / "vhdl_configuration" / f"{snippet}.html", + snippet, + ) + + for snippet in [ + "test_runner_entity", + ]: + highlight_code( + root / "test_runner.vhd", + root / ".." / ".." / "img" / "vhdl_configuration" / f"{snippet}.html", + snippet, + ) + + +extract_snippets() + +testbenches = [] +for _root, _dirs, files in walk(root): + for f in files: + if f.startswith("tb_") and f.endswith(".vhd"): + testbenches.append(Path(f).stem) + +test_patterns = [f"lib.{testbench}.*" for testbench in testbenches] +for testbench, test_pattern in zip(testbenches, test_patterns): + args.test_patterns = [test_pattern] + + vu = VUnit.from_args(args=args) + vu.add_vhdl_builtins() + lib = vu.add_library("lib") + lib.add_source_files(root / "*.vhd") + + # start_snippet create_vunit_configuration_for_selecting_dut + tb = lib.test_bench("tb_selecting_dut_with_generics") + + for dut_arch, width in itertools.product(["rtl", "behavioral"], [8, 16]): + tb.add_config( + name=f"{dut_arch}_{width}", + generics=dict(width=width, dff_arch=dut_arch), + ) + # end_snippet create_vunit_configuration_for_selecting_dut + + # VHDL configurations are treated as a special case of the broader VUnit configuration + # concept. As such the configuration can be extended beyond the capabilities of a + # pure VHDL configuration. For example, by running with different generic values. + + # start_snippet create_vunit_configuration_for_selecting_dut_with_a_vhdl_configuration + tb = lib.test_bench("tb_selecting_dut_with_vhdl_configuration") + + for dut_arch, width in itertools.product(["rtl", "behavioral"], [8, 16]): + tb.add_config( + name=f"{dut_arch}_{width}", + generics=dict(width=width), + vhdl_configuration_name=dut_arch, + ) + # end_snippet create_vunit_configuration_for_selecting_dut_with_a_vhdl_configuration + + # A top-level VHDL configuration is bound to an entity, i.e. the testbench. However, + # when handled as part of VUnit configurations it can also be applied to a + # single test case + + # start_snippet vhdl_configuration_on_a_test_case + tb.test("Test reset").add_config(name="rtl_32", generics=dict(width=32), vhdl_configuration_name="rtl") + # end_snippet vhdl_configuration_on_a_test_case + + # If the test runner is placed in a component instantiated into the testbench, different architectures of that + # component can implement different tests and VHDL configurations can be used to select what test to run. + # This is the approach taken by a traditional OSVVM testbench. In VUnit, such a test becomes a VUnit configuration + # selecting the associated VHDL configuration rather than a VUnit test case, but that is of less importance. Note that + # this approach is limited in that the test runner architecture can't contain a test suite with explicit test cases + # (run function calls) but only the test_runner_setup and test_runner_cleanup calls. Should you need multiple test + # suites sharing the same test fixture (the DUT and the surrounding verification components), the proper approach + # is to put each test suite in its own testbench and make the test fixture a component reused between the testbenches. + # That approach do not require any VHDL configurations. + + # start_snippet create_vunit_configuration_for_selecting_dut_and_runner_with_a_vhdl_configuration + tb = lib.test_bench("tb_selecting_test_runner_with_vhdl_configuration") + + for dut_arch, width, test_case_name in itertools.product( + ["rtl", "behavioral"], [8, 16], ["test_reset", "test_state_change"] + ): + vhdl_configuration_name = f"{test_case_name}_{dut_arch}" + tb.add_config( + name=f"{vhdl_configuration_name}_{width}", + generics=dict(width=width), + vhdl_configuration_name=vhdl_configuration_name, + ) + # end_snippet create_vunit_configuration_for_selecting_dut_and_runner_with_a_vhdl_configuration + + stringio = StringIO() + _stdout = sys.stdout + sys.stdout = stringio + + try: + vu.main() + except SystemExit: + std_out = stringio.getvalue() + sys.stdout = _stdout + print(std_out) + + if args.list: + (root / f"{testbench}_stdout.txt").write_text(f"> python run.py --list\n" + std_out) + highlight_log( + root / f"{testbench}_stdout.txt", + root / ".." / ".." / "img" / "vhdl_configuration" / f"{testbench}_stdout.html", + ) diff --git a/docs/blog/src/vhdl_configuration/tb_selecting_dut_with_generics.vhd b/docs/blog/src/vhdl_configuration/tb_selecting_dut_with_generics.vhd new file mode 100644 index 000000000..bf968ce0d --- /dev/null +++ b/docs/blog/src/vhdl_configuration/tb_selecting_dut_with_generics.vhd @@ -0,0 +1,104 @@ +-- This Source Code Form is subject to the terms of the Mozilla Public +-- License, v. 2.0. If a copy of the MPL was not distributed with this file, +-- You can obtain one at http://mozilla.org/MPL/2.0/. +-- +-- Copyright (c) 2014-2023, Lars Asplund lars.anders.asplund@gmail.com +-- +-- Description: This is an example of a testbench using a generic instead +-- of VHDL configurations to select the DUT to run. Without VHDL configurations +-- the width generic to the dff entity can be exposed and modified at the top-level + +library vunit_lib; +context vunit_lib.vunit_context; + +library ieee; +use ieee.std_logic_1164.all; + +-- start_snippet selecting_dut_with_generics +entity tb_selecting_dut_with_generics is + generic( + runner_cfg : string; + width : positive; + dff_arch : string + ); +end entity; + +architecture tb of tb_selecting_dut_with_generics is + -- start_folding ... + constant clk_period : time := 10 ns; + + signal reset : std_logic; + signal clk : std_logic := '0'; + signal d : std_logic_vector(width - 1 downto 0); + signal q : std_logic_vector(width - 1 downto 0); + -- end_folding ... +begin + test_runner : process + begin + test_runner_setup(runner, runner_cfg); + + while test_suite loop + if run("Test reset") then + -- start_folding ... + d <= (others => '1'); + reset <= '1'; + wait until rising_edge(clk); + wait for 0 ns; + check_equal(q, 0); + -- end_folding ... + elsif run("Test state change") then + -- start_folding ... + reset <= '0'; + + d <= (others => '1'); + wait until rising_edge(clk); + wait for 0 ns; + check_equal(q, std_logic_vector'(q'range => '1')); + + d <= (others => '0'); + wait until rising_edge(clk); + wait for 0 ns; + check_equal(q, 0); + -- end_folding ... + end if; + end loop; + + test_runner_cleanup(runner); + end process; + + test_runner_watchdog(runner, 10 * clk_period); + + test_fixture : block is + begin + clk <= not clk after clk_period / 2; + + dut_selection : if dff_arch = "rtl" generate + dut : entity work.dff(rtl) + generic map( + width => width + ) + port map( + clk => clk, + reset => reset, + d => d, + q => q + ); + + elsif dff_arch = "behavioral" generate + dut : entity work.dff(behavioral) + generic map( + width => width + ) + port map( + clk => clk, + reset => reset, + d => d, + q => q + ); + + else generate + error("Unknown DFF architecture"); + end generate; + end block; +end architecture; +-- end_snippet selecting_dut_with_generics diff --git a/docs/blog/src/vhdl_configuration/tb_selecting_dut_with_vhdl_configuration.vhd b/docs/blog/src/vhdl_configuration/tb_selecting_dut_with_vhdl_configuration.vhd new file mode 100644 index 000000000..4351dc2af --- /dev/null +++ b/docs/blog/src/vhdl_configuration/tb_selecting_dut_with_vhdl_configuration.vhd @@ -0,0 +1,121 @@ +-- This Source Code Form is subject to the terms of the Mozilla Public +-- License, v. 2.0. If a copy of the MPL was not distributed with this file, +-- You can obtain one at http://mozilla.org/MPL/2.0/. +-- +-- Copyright (c) 2014-2023, Lars Asplund lars.anders.asplund@gmail.com +-- +-- Description: This is an example of a testbench using VHDL configurations +-- to select DUT architecture + +library vunit_lib; +context vunit_lib.vunit_context; + +library ieee; +use ieee.std_logic_1164.all; + +-- start_snippet selecting_dut_with_vhdl_configuration +entity tb_selecting_dut_with_vhdl_configuration is + generic( + runner_cfg : string; + width : positive + ); +end entity; + +architecture tb of tb_selecting_dut_with_vhdl_configuration is + -- start_folding ... + constant clk_period : time := 10 ns; + + signal reset : std_logic; + signal clk : std_logic := '0'; + signal d : std_logic_vector(width - 1 downto 0); + signal q : std_logic_vector(width - 1 downto 0); + -- end_folding ... + + -- Component declaration + component dff is + generic( + width : positive := width + ); + port( + clk : in std_logic; + reset : in std_logic; + d : in std_logic_vector(width - 1 downto 0); + q : out std_logic_vector(width - 1 downto 0) + ); + end component; +begin + test_runner : process + begin + test_runner_setup(runner, runner_cfg); + + while test_suite loop + if run("Test reset") then + -- start_folding ... + d <= (others => '1'); + reset <= '1'; + wait until rising_edge(clk); + wait for 0 ns; + check_equal(q, 0); + -- end_folding ... + elsif run("Test state change") then + -- start_folding ... + reset <= '0'; + + d <= (others => '1'); + wait until rising_edge(clk); + wait for 0 ns; + check_equal(q, std_logic_vector'(q'range => '1')); + + d <= (others => '0'); + wait until rising_edge(clk); + wait for 0 ns; + check_equal(q, 0); + -- end_folding ... + end if; + end loop; + + test_runner_cleanup(runner); + end process; + + test_runner_watchdog(runner, 10 * clk_period); + + test_fixture : block is + begin + clk <= not clk after clk_period / 2; + + -- Component instantiation + dut : component dff + generic map( + width => width + ) + port map( + clk => clk, + reset => reset, + d => d, + q => q + ); + end block; +end architecture; + +-- Configuration declarations +configuration rtl of tb_selecting_dut_with_vhdl_configuration is + for tb + for test_fixture + for dut : dff + use entity work.dff(rtl); + end for; + end for; + end for; +end; + +configuration behavioral of tb_selecting_dut_with_vhdl_configuration is + for tb + for test_fixture + for dut : dff + use entity work.dff(behavioral); + end for; + end for; + end for; +end; +-- end_snippet selecting_dut_with_vhdl_configuration + diff --git a/docs/blog/src/vhdl_configuration/tb_selecting_test_runner_with_vhdl_configuration.vhd b/docs/blog/src/vhdl_configuration/tb_selecting_test_runner_with_vhdl_configuration.vhd new file mode 100644 index 000000000..a85bdfcc3 --- /dev/null +++ b/docs/blog/src/vhdl_configuration/tb_selecting_test_runner_with_vhdl_configuration.vhd @@ -0,0 +1,89 @@ +-- This Source Code Form is subject to the terms of the Mozilla Public +-- License, v. 2.0. If a copy of the MPL was not distributed with this file, +-- You can obtain one at http://mozilla.org/MPL/2.0/. +-- +-- Copyright (c) 2014-2023, Lars Asplund lars.anders.asplund@gmail.com +-- +-- Description: This is an example of a testbench using separate architectures +-- of a test runner entity to define different tests. This is a structure +-- found in OSVVM-native testbenches + +library vunit_lib; +context vunit_lib.vunit_context; + +library ieee; +use ieee.std_logic_1164.all; + +entity tb_selecting_test_runner_with_vhdl_configuration is + generic( + runner_cfg : string; + width : positive + ); +end entity; + +architecture tb of tb_selecting_test_runner_with_vhdl_configuration is + constant clk_period : time := 10 ns; + + signal reset : std_logic; + signal clk : std_logic := '0'; + signal d : std_logic_vector(width - 1 downto 0); + signal q : std_logic_vector(width - 1 downto 0); + + component test_runner is + generic( + clk_period : time; + width : positive; + nested_runner_cfg : string + ); + port( + reset : out std_logic; + clk : in std_logic; + d : out std_logic_vector(width - 1 downto 0); + q : in std_logic_vector(width - 1 downto 0) + ); + end component; + + component dff is + generic( + width : positive := width + ); + port( + clk : in std_logic; + reset : in std_logic; + d : in std_logic_vector(width - 1 downto 0); + q : out std_logic_vector(width - 1 downto 0) + ); + end component; + +begin + -- start_snippet test_runner_component_instantiation + test_runner_inst : component test_runner + generic map( + clk_period => clk_period, + width => width, + nested_runner_cfg => runner_cfg + ) + port map( + reset => reset, + clk => clk, + d => d, + q => q + ); + -- end_snippet test_runner_component_instantiation + + test_fixture : block is + begin + clk <= not clk after clk_period / 2; + + dut : component dff + generic map( + width => width + ) + port map( + clk => clk, + reset => reset, + d => d, + q => q + ); + end block; +end architecture; diff --git a/docs/blog/src/vhdl_configuration/test_reset.vhd b/docs/blog/src/vhdl_configuration/test_reset.vhd new file mode 100644 index 000000000..bc9023571 --- /dev/null +++ b/docs/blog/src/vhdl_configuration/test_reset.vhd @@ -0,0 +1,63 @@ +-- This Source Code Form is subject to the terms of the Mozilla Public +-- License, v. 2.0. If a copy of the MPL was not distributed with this file, +-- You can obtain one at http://mozilla.org/MPL/2.0/. +-- +-- Copyright (c) 2014-2023, Lars Asplund lars.anders.asplund@gmail.com + +library vunit_lib; +context vunit_lib.vunit_context; + +library ieee; +use ieee.std_logic_1164.all; + +-- start_snippet test_reset_architecture_of_test_runner +architecture test_reset_architecture of test_runner is +begin + main : process + begin + test_runner_setup(runner, nested_runner_cfg); + + -- start_folding -- Test code here + d <= (others => '1'); + reset <= '1'; + wait until rising_edge(clk); + wait for 0 ns; + check_equal(q, 0); + -- end_folding -- Test code here + + test_runner_cleanup(runner); + end process; + + test_runner_watchdog(runner, 10 * clk_period); +end; +-- end_snippet test_reset_architecture_of_test_runner + +-- start_snippet test_reset_configurations +configuration test_reset_behavioral of tb_selecting_test_runner_with_vhdl_configuration is + for tb + for test_runner_inst : test_runner + use entity work.test_runner(test_reset_architecture); + end for; + + for test_fixture + for dut : dff + use entity work.dff(behavioral); + end for; + end for; + end for; +end; + +configuration test_reset_rtl of tb_selecting_test_runner_with_vhdl_configuration is + for tb + for test_runner_inst : test_runner + use entity work.test_runner(test_reset_architecture); + end for; + + for test_fixture + for dut : dff + use entity work.dff(rtl); + end for; + end for; + end for; +end; +-- end_snippet test_reset_configurations diff --git a/docs/blog/src/vhdl_configuration/test_runner.vhd b/docs/blog/src/vhdl_configuration/test_runner.vhd new file mode 100644 index 000000000..32366bfc8 --- /dev/null +++ b/docs/blog/src/vhdl_configuration/test_runner.vhd @@ -0,0 +1,24 @@ +-- This Source Code Form is subject to the terms of the Mozilla Public +-- License, v. 2.0. If a copy of the MPL was not distributed with this file, +-- You can obtain one at http://mozilla.org/MPL/2.0/. +-- +-- Copyright (c) 2014-2023, Lars Asplund lars.anders.asplund@gmail.com + +library ieee; +use ieee.std_logic_1164.all; + +-- start_snippet test_runner_entity +entity test_runner is + generic( + clk_period : time; + width : positive; + nested_runner_cfg : string + ); + port( + reset : out std_logic; + clk : in std_logic; + d : out std_logic_vector(width - 1 downto 0); + q : in std_logic_vector(width - 1 downto 0) + ); +end entity; +-- end_snippet test_runner_entity diff --git a/docs/blog/src/vhdl_configuration/test_state_change.vhd b/docs/blog/src/vhdl_configuration/test_state_change.vhd new file mode 100644 index 000000000..0aba91c84 --- /dev/null +++ b/docs/blog/src/vhdl_configuration/test_state_change.vhd @@ -0,0 +1,63 @@ +-- This Source Code Form is subject to the terms of the Mozilla Public +-- License, v. 2.0. If a copy of the MPL was not distributed with this file, +-- You can obtain one at http://mozilla.org/MPL/2.0/. +-- +-- Copyright (c) 2014-2023, Lars Asplund lars.anders.asplund@gmail.com + +library vunit_lib; +context vunit_lib.vunit_context; + +library ieee; +use ieee.std_logic_1164.all; + +architecture test_state_change_architecture of test_runner is +begin + main : process + begin + test_runner_setup(runner, nested_runner_cfg); + + reset <= '0'; + + d <= (others => '1'); + wait until rising_edge(clk); + wait for 0 ns; + check_equal(q, std_logic_vector'(q'range => '1')); + + d <= (others => '0'); + wait until rising_edge(clk); + wait for 0 ns; + check_equal(q, 0); + + test_runner_cleanup(runner); + end process; + + test_runner_watchdog(runner, 10 * clk_period); +end; + +configuration test_state_change_behavioral of tb_selecting_test_runner_with_vhdl_configuration is + for tb + for test_runner_inst : test_runner + use entity work.test_runner(test_state_change_architecture); + end for; + + for test_fixture + for dut : dff + use entity work.dff(behavioral); + end for; + end for; + end for; +end; + +configuration test_state_change_rtl of tb_selecting_test_runner_with_vhdl_configuration is + for tb + for test_runner_inst : test_runner + use entity work.test_runner(test_state_change_architecture); + end for; + + for test_fixture + for dut : dff + use entity work.dff(rtl); + end for; + end for; + end for; +end; diff --git a/docs/news.d/179.feature.rst b/docs/news.d/179.feature.rst new file mode 100644 index 000000000..2199b0fae --- /dev/null +++ b/docs/news.d/179.feature.rst @@ -0,0 +1 @@ +Added support for simulating top-level VHDL configurations. diff --git a/docs/news.d/951.feature.rst b/docs/news.d/951.feature.rst new file mode 100644 index 000000000..2199b0fae --- /dev/null +++ b/docs/news.d/951.feature.rst @@ -0,0 +1 @@ +Added support for simulating top-level VHDL configurations. diff --git a/examples/vhdl/vhdl_configuration/dff.vhd b/examples/vhdl/vhdl_configuration/dff.vhd index b766c385d..acac60107 100644 --- a/examples/vhdl/vhdl_configuration/dff.vhd +++ b/examples/vhdl/vhdl_configuration/dff.vhd @@ -32,16 +32,6 @@ begin end process; end; -configuration dff_rtl of tb_selecting_dut_with_vhdl_configuration is - for tb - for test_fixture - for dut : dff - use entity work.dff(rtl); - end for; - end for; - end for; -end; - architecture behavioral of dff is begin process @@ -51,12 +41,3 @@ begin end process; end; -configuration dff_behavioral of tb_selecting_dut_with_vhdl_configuration is - for tb - for test_fixture - for dut : dff - use entity work.dff(behavioral); - end for; - end for; - end for; -end; diff --git a/examples/vhdl/vhdl_configuration/run.py b/examples/vhdl/vhdl_configuration/run.py index 50546bdcb..30895ed49 100644 --- a/examples/vhdl/vhdl_configuration/run.py +++ b/examples/vhdl/vhdl_configuration/run.py @@ -20,18 +20,18 @@ # pure VHDL configuration. For example, by running with different generic values. tb = lib.test_bench("tb_selecting_dut_with_vhdl_configuration") -for vhdl_configuration_name in ["dff_rtl", "dff_behavioral"]: +for dut_architecture in ["rtl", "behavioral"]: for width in [8, 16]: tb.add_config( - name=f"{vhdl_configuration_name}_{width}", + name=f"{dut_architecture}_{width}", generics=dict(width=width), - vhdl_configuration_name=vhdl_configuration_name, + vhdl_configuration_name=dut_architecture, ) # A top-level VHDL configuration is bound to an entity, i.e. the testbench. However, # when handled as part of VUnit configurations it can also be applied to a # single test case -tb.test("Test reset").add_config(name="dff_rtl_32", generics=dict(width=32), vhdl_configuration_name="dff_rtl") +tb.test("Test reset").add_config(name="rtl_32", generics=dict(width=32), vhdl_configuration_name="rtl") # If the test runner is placed in a component instantiated into the testbench, different architectures of that @@ -44,12 +44,14 @@ # is to put each test suite in its own testbench and make the test fixture a component reused between the testbenches. # That approach do not require any VHDL configurations. tb = lib.test_bench("tb_selecting_test_runner_with_vhdl_configuration") -for vhdl_configuration_name in ["test_reset", "test_state_change"]: - for width in [8, 16]: - tb.add_config( - name=f"{vhdl_configuration_name}_{width}", - generics=dict(width=width), - vhdl_configuration_name=vhdl_configuration_name, - ) +for test_case_name in ["test_reset", "test_state_change"]: + for dut_architecture in ["rtl", "behavioral"]: + vhdl_configuration_name = f"{test_case_name}_{dut_architecture}" + for width in [8, 16]: + tb.add_config( + name=f"{vhdl_configuration_name}_{width}", + generics=dict(width=width), + vhdl_configuration_name=vhdl_configuration_name, + ) vu.main() diff --git a/examples/vhdl/vhdl_configuration/tb_selecting_dut_with_vhdl_configuration.vhd b/examples/vhdl/vhdl_configuration/tb_selecting_dut_with_vhdl_configuration.vhd index 149c898f0..2d45baf68 100644 --- a/examples/vhdl/vhdl_configuration/tb_selecting_dut_with_vhdl_configuration.vhd +++ b/examples/vhdl/vhdl_configuration/tb_selecting_dut_with_vhdl_configuration.vhd @@ -75,7 +75,7 @@ begin begin clk <= not clk after clk_period / 2; - dut : dff + dut : component dff generic map( width => width ) @@ -87,3 +87,24 @@ begin ); end block; end architecture; + +configuration rtl of tb_selecting_dut_with_vhdl_configuration is + for tb + for test_fixture + for dut : dff + use entity work.dff(rtl); + end for; + end for; + end for; +end; + +configuration behavioral of tb_selecting_dut_with_vhdl_configuration is + for tb + for test_fixture + for dut : dff + use entity work.dff(behavioral); + end for; + end for; + end for; +end; + diff --git a/examples/vhdl/vhdl_configuration/tb_selecting_test_runner_with_vhdl_configuration.vhd b/examples/vhdl/vhdl_configuration/tb_selecting_test_runner_with_vhdl_configuration.vhd index be076ddd9..4ff6c4302 100644 --- a/examples/vhdl/vhdl_configuration/tb_selecting_test_runner_with_vhdl_configuration.vhd +++ b/examples/vhdl/vhdl_configuration/tb_selecting_test_runner_with_vhdl_configuration.vhd @@ -43,8 +43,20 @@ architecture tb of tb_selecting_test_runner_with_vhdl_configuration is ); end component; + component dff is + generic( + width : positive := width + ); + port( + clk : in std_logic; + reset : in std_logic; + d : in std_logic_vector(width - 1 downto 0); + q : out std_logic_vector(width - 1 downto 0) + ); + end component; + begin - test_runner_inst : test_runner + test_runner_inst : component test_runner generic map( clk_period => clk_period, width => width, @@ -61,7 +73,7 @@ begin begin clk <= not clk after clk_period / 2; - dut : entity work.dff(rtl) + dut : component dff generic map( width => width ) diff --git a/examples/vhdl/vhdl_configuration/test_reset.vhd b/examples/vhdl/vhdl_configuration/test_reset.vhd index 76f5f0857..e1c48fb37 100644 --- a/examples/vhdl/vhdl_configuration/test_reset.vhd +++ b/examples/vhdl/vhdl_configuration/test_reset.vhd @@ -28,10 +28,30 @@ begin test_runner_watchdog(runner, 10 * clk_period); end; -configuration test_reset of tb_selecting_test_runner_with_vhdl_configuration is +configuration test_reset_behavioral of tb_selecting_test_runner_with_vhdl_configuration is for tb for test_runner_inst : test_runner use entity work.test_runner(test_reset_a); end for; + + for test_fixture + for dut : dff + use entity work.dff(behavioral); + end for; + end for; + end for; +end; + +configuration test_reset_rtl of tb_selecting_test_runner_with_vhdl_configuration is + for tb + for test_runner_inst : test_runner + use entity work.test_runner(test_reset_a); + end for; + + for test_fixture + for dut : dff + use entity work.dff(rtl); + end for; + end for; end for; end; diff --git a/examples/vhdl/vhdl_configuration/test_state_change.vhd b/examples/vhdl/vhdl_configuration/test_state_change.vhd index aadf97bcd..5037ca080 100644 --- a/examples/vhdl/vhdl_configuration/test_state_change.vhd +++ b/examples/vhdl/vhdl_configuration/test_state_change.vhd @@ -34,10 +34,30 @@ begin test_runner_watchdog(runner, 10 * clk_period); end; -configuration test_state_change of tb_selecting_test_runner_with_vhdl_configuration is +configuration test_state_change_behavioral of tb_selecting_test_runner_with_vhdl_configuration is for tb for test_runner_inst : test_runner use entity work.test_runner(test_state_change_a); end for; + + for test_fixture + for dut : dff + use entity work.dff(behavioral); + end for; + end for; + end for; +end; + +configuration test_state_change_rtl of tb_selecting_test_runner_with_vhdl_configuration is + for tb + for test_runner_inst : test_runner + use entity work.test_runner(test_state_change_a); + end for; + + for test_fixture + for dut : dff + use entity work.dff(rtl); + end for; + end for; end for; end;