Skip to content

Commit

Permalink
Added VHDL configuration examples.
Browse files Browse the repository at this point in the history
  • Loading branch information
LarsAsplund committed Jul 21, 2023
1 parent 9e692ce commit 8da5d82
Show file tree
Hide file tree
Showing 8 changed files with 404 additions and 0 deletions.
62 changes: 62 additions & 0 deletions examples/vhdl/vhdl_configuration/dff.vhd
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
-- 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;

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
begin
wait until rising_edge(clk);
q <= (others => '0') when reset else d;
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;
55 changes: 55 additions & 0 deletions examples/vhdl/vhdl_configuration/run.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
#!/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

from pathlib import Path
from vunit import VUnit

vu = VUnit.from_argv()
vu.add_vhdl_builtins()
lib = vu.add_library("lib")
root = Path(__file__).parent
lib.add_source_files(root / "*.vhd")

# 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.
tb = lib.test_bench("tb_selecting_dut_with_vhdl_configuration")

for vhdl_configuration_name in ["dff_rtl", "dff_behavioral"]:
for width in [8, 16]:
tb.add_config(
name=f"{vhdl_configuration_name}_{width}",
generics=dict(width=width),
vhdl_configuration_name=vhdl_configuration_name,
)

# 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")


# 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.
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,
)

vu.main()
Original file line number Diff line number Diff line change
@@ -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 VHDL configurations
-- to select DUT architecture

library vunit_lib;
context vunit_lib.vunit_context;

library ieee;
use ieee.std_logic_1164.all;

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
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 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
d <= (others => '1');
reset <= '1';
wait until rising_edge(clk);
wait for 0 ns;
check_equal(q, 0);

elsif run("Test state change") then
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 if;
end loop;

test_runner_cleanup(runner);
end process;

test_fixture : block is
begin
clk <= not clk after clk_period / 2;

dut : dff
generic map(
width => width
)
port map(
clk => clk,
reset => reset,
d => d,
q => q
);
end block;
end architecture;
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
-- 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;

begin
test_runner_inst : 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
);

test_fixture : block is
begin
clk <= not clk after clk_period / 2;

dut : entity work.dff(rtl)
generic map(
width => width
)
port map(
clk => clk,
reset => reset,
d => d,
q => q
);
end block;
end architecture;
37 changes: 37 additions & 0 deletions examples/vhdl/vhdl_configuration/test_reset.vhd
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
-- 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_reset_a of test_runner is
begin
main : process
begin
test_runner_setup(runner, nested_runner_cfg);

d <= (others => '1');
reset <= '1';
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_reset 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;
end for;
end;
22 changes: 22 additions & 0 deletions examples/vhdl/vhdl_configuration/test_runner.vhd
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
-- 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 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;
43 changes: 43 additions & 0 deletions examples/vhdl/vhdl_configuration/test_state_change.vhd
Original file line number Diff line number Diff line change
@@ -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 vunit_lib;
context vunit_lib.vunit_context;

library ieee;
use ieee.std_logic_1164.all;

architecture test_state_change_a 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 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;
end for;
end;
Loading

0 comments on commit 8da5d82

Please sign in to comment.