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 Jan 2, 2022
1 parent d1330d6 commit ad8dbf2
Show file tree
Hide file tree
Showing 12 changed files with 677 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-2021, 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;
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
-- 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-2021, Lars Asplund lars.anders.asplund@gmail.com
--
-- Description: Instead of having a testbench containing a shared test fixture
-- and then use VHDL configurations to select different test runners implementing
-- different tests one can flip things upside down. Each test become a separate
-- top-level testbench and the shared test fixture is placed in a separate entity
-- imported by each tetbench.

library vunit_lib;
context vunit_lib.vunit_context;

library ieee;
use ieee.std_logic_1164.all;

entity tb_reset is
generic(
runner_cfg : string;
width : positive
);
end entity;

architecture tb of tb_reset is
constant clk_period : time := 10 ns;

signal reset : std_logic;
signal clk : std_logic;
signal d : std_logic_vector(width - 1 downto 0);
signal q : std_logic_vector(width - 1 downto 0);
begin
text_fixture_inst : entity work.test_fixture
generic map(
width => width,
clk_period => clk_period
)
port map(
clk => clk,
reset => reset,
d => d,
q => q
);

test_runner : process
begin
test_runner_setup(runner, 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;

end architecture;
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
-- 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-2021, 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;

entity tb_selecting_dut_with_generate_statement is
generic(
runner_cfg : string;
width : positive;
dff_arch : string
);
end entity;

architecture tb of tb_selecting_dut_with_generate_statement 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);
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_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;
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
-- 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-2021, Lars Asplund lars.anders.asplund@gmail.com
--
-- Description: Instead of having a testbench containing a shared test fixture
-- and then use VHDL configurations to select different test runners implementing
-- different tests one can flip things upside down. Each test become a separate
-- top-level testbench and the shared test fixture is placed in a separate entity
-- imported by each tetbench.

library vunit_lib;
context vunit_lib.vunit_context;

library ieee;
use ieee.std_logic_1164.all;

entity tb_state_change is
generic(
runner_cfg : string;
width : positive
);
end entity;

architecture tb of tb_state_change is
constant clk_period : time := 10 ns;

signal reset : std_logic;
signal clk : std_logic;
signal d : std_logic_vector(width - 1 downto 0);
signal q : std_logic_vector(width - 1 downto 0);
begin
text_fixture_inst : entity work.test_fixture
generic map(
width => width,
clk_period => clk_period
)
port map(
clk => clk,
reset => reset,
d => d,
q => q
);

test_runner : process
begin
test_runner_setup(runner, 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;

end architecture;
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
-- 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-2021, Lars Asplund lars.anders.asplund@gmail.com

library ieee;
use ieee.std_logic_1164.all;

entity test_fixture is
generic(
width : positive := 8;
clk_period : time
);
port(
clk : out std_logic := '0';
reset : in std_logic;
d : in std_logic_vector(width - 1 downto 0);
q : out std_logic_vector(width - 1 downto 0)
);
end entity;

architecture tb of test_fixture 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 architecture;
60 changes: 60 additions & 0 deletions examples/vhdl/vhdl_configuration/run.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#!/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-2021, Lars Asplund lars.anders.asplund@gmail.com

from pathlib import Path
from vunit import VUnit
from vunit.json4vhdl import encode_json, b16encode

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

# VHDL configurations are detected automatically and 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 adding a post_check function. The exception is generics since VHDL doesn't allow
# generics to be combined with configurations. Workarounds for this limitation can be
# found in the handling_generics_limitation directory

# Get the VHDL-defined configurations from test or testbench objects using a pattern matching
# configurations of interest.
tb = lib.test_bench("tb_selecting_dut_with_vhdl_configuration")
configurations = tb.get_configs("dff_*")

# Remember to run the run script with the -v flag to see the message from the dummy post_check
def post_check(output_path):
print("Running post-check")

return True


configurations.set_post_check(post_check)

# The testbenches in the handling_generics_limitation directory are examples of how the generics
# limitation of VHDL configurations can be worked around. This allow us to create configurations
# with different settings for the DUT width generic

# This testbench replaces VHDL configurations with generate statements
tb = lib.test_bench("tb_selecting_dut_with_generate_statement")
for width in [8, 32]:
for arch in ["rtl", "behavioral"]:
tb.add_config(name=f"dff_{arch}_width={width}", generics=dict(dff_arch=arch, width=width))

# Instead of having a testbench containing a shared test fixture
# and then use VHDL configurations to select different test runners implementing
# different tests one can flip things upside down. Each test become a separate
# top-level testbench and the shared test fixture is placed in a separate entity
# imported by each tetbench.
for tb_name in ["tb_reset", "tb_state_change"]:
tb = lib.test_bench(tb_name)
for width in [8, 32]:
tb.add_config(name=f"width={width}", generics=dict(width=width))

vu.main()
Loading

0 comments on commit ad8dbf2

Please sign in to comment.