Skip to content

Commit

Permalink
Add support package for VCs.
Browse files Browse the repository at this point in the history
  • Loading branch information
LarsAsplund committed Nov 3, 2024
1 parent 31493fc commit 32c821c
Show file tree
Hide file tree
Showing 2 changed files with 245 additions and 0 deletions.
143 changes: 143 additions & 0 deletions vunit/vhdl/verification_components/src/vc_pkg.vhd
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
-- 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-2024, Lars Asplund [email protected]
--
-- This package contains common functionality for VCs.

context work.vunit_context;
context work.com_context;

package vc_pkg is
type unexpected_msg_type_policy_t is (fail, ignore);

type std_cfg_t is record
p_id : id_t;
p_actor : actor_t;
p_logger : logger_t;
p_checker : checker_t;
p_unexpected_msg_type_policy : unexpected_msg_type_policy_t;
end record;

constant null_std_cfg : std_cfg_t := (
p_id => null_id,
p_actor => null_actor,
p_logger => null_logger,
p_checker => null_checker,
p_unexpected_msg_type_policy => ignore
);

-- Creates a standard VC configuration with an id, an actor, a logger, a
-- checker, and an unexpected message type policy.
--
-- If id = null_id, the id will be assigned the name provider:vc_name:n where n is 1
-- for the first instance and increasing with one for every additional instance.
--
-- The id must not have an associated actor before the call as that may indicate
-- several users of the same actor.
--
-- If a logger exist for the id, it will be reused. If not, a new logger is created.
-- A new checker is created that reports to the logger.
impure function create_std_cfg(
id : id_t := null_id;
provider : string := "";
vc_name : string := "";
unexpected_msg_type_policy : unexpected_msg_type_policy_t := fail
) return std_cfg_t;

-- These functions extracts information from the standard VC configuration
impure function get_id(std_cfg : std_cfg_t) return id_t;
impure function get_actor(std_cfg : std_cfg_t) return actor_t;
impure function get_logger(std_cfg : std_cfg_t) return logger_t;
impure function get_checker(std_cfg : std_cfg_t) return checker_t;
impure function unexpected_msg_type_policy(std_cfg : std_cfg_t) return unexpected_msg_type_policy_t;

-- Handle messages with unexpected message type according to the standard configuration
procedure unexpected_msg_type(msg_type : msg_type_t; std_cfg : std_cfg_t);

end package;

package body vc_pkg is
constant vc_pkg_logger : logger_t := get_logger("vunit_lib:vc_pkg");
constant vc_pkg_checker : checker_t := new_checker(vc_pkg_logger);

impure function create_std_cfg(
id : id_t := null_id;
provider : string := "";
vc_name : string := "";
unexpected_msg_type_policy : unexpected_msg_type_policy_t := fail
) return std_cfg_t is
variable result : std_cfg_t;
variable provider_id : id_t;
variable vc_id : id_t;
begin
if id /= null_id then
result.p_id := id;
else
if provider = "" then
check_failed(vc_pkg_checker, "A provider must be provided.");

-- Simplifies testing when vc_pkg_checker logger is mocked
return null_std_cfg;
end if;

if vc_name = "" then
check_failed(vc_pkg_checker, "A VC name must be provided.");

-- Simplifies testing when vc_pkg_checker logger is mocked
return null_std_cfg;
end if;

provider_id := get_id(provider);
vc_id := get_id(vc_name, parent => provider_id);
result.p_id := get_id(to_string(num_children(vc_id) + 1), parent => vc_id);
end if;

result.p_unexpected_msg_type_policy := unexpected_msg_type_policy;

if find(result.p_id, enable_deferred_creation => false) /= null_actor then
check_failed(vc_pkg_checker, "An actor already exists for " & full_name(result.p_id) & ".");
else
result.p_actor := new_actor(result.p_id);
end if;

result.p_logger := get_logger(result.p_id);
result.p_checker := new_checker(result.p_logger);

return result;
end;

impure function get_id(std_cfg : std_cfg_t) return id_t is
begin
return std_cfg.p_id;
end;

impure function get_actor(std_cfg : std_cfg_t) return actor_t is
begin
return std_cfg.p_actor;
end;

impure function get_logger(std_cfg : std_cfg_t) return logger_t is
begin
return std_cfg.p_logger;
end;

impure function get_checker(std_cfg : std_cfg_t) return checker_t is
begin
return std_cfg.p_checker;
end;

impure function unexpected_msg_type_policy(std_cfg : std_cfg_t) return unexpected_msg_type_policy_t is
begin
return std_cfg.p_unexpected_msg_type_policy;
end;

procedure unexpected_msg_type(msg_type : msg_type_t;
std_cfg : std_cfg_t) is
begin
if unexpected_msg_type_policy(std_cfg) = fail then
unexpected_msg_type(msg_type, get_logger(std_cfg));
end if;
end;
end package body;
102 changes: 102 additions & 0 deletions vunit/vhdl/verification_components/test/tb_vc_pkg.vhd
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
-- 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-2024, Lars Asplund [email protected]

library vunit_lib;
context vunit_lib.vunit_context;
context work.com_context;
use work.vc_pkg.all;

entity tb_vc_pkg is
generic(runner_cfg : string);
end entity;

architecture a of tb_vc_pkg is
begin

main : process
variable std_cfg : std_cfg_t;
variable id : id_t;
variable actor : actor_t;

constant vc_pkg_logger : logger_t := get_logger("vunit_lib:vc_pkg");
constant unknown_msg_type : msg_type_t := new_msg_type("unknown_msg");
begin
test_runner_setup(runner, runner_cfg);
while test_suite loop
if run("Test that provider must be supplied with null_id") then
mock(vc_pkg_logger, error);
std_cfg := create_std_cfg(vc_name => "my_vc");
check_only_log(vc_pkg_logger, "A provider must be provided.", error);
unmock(vc_pkg_logger);

elsif run("Test that vc_name must be supplied with null_id") then
mock(vc_pkg_logger, error);
std_cfg := create_std_cfg(provider => "provider");
check_only_log(vc_pkg_logger, "A VC name must be provided.", error);
unmock(vc_pkg_logger);

elsif run("Test standard config with specified id") then
id := get_id("id");
std_cfg := create_std_cfg(id => id);
check(std_cfg.p_id = id);
check(std_cfg.p_actor = find(id, enable_deferred_creation => false));
check(std_cfg.p_logger = get_logger(id));
check(get_logger(std_cfg.p_checker) = get_logger(id));
check(std_cfg.p_unexpected_msg_type_policy = fail);

elsif run("Test standard config with null_id") then
for instance in 1 to 3 loop
std_cfg := create_std_cfg(provider => "provider", vc_name => "vc_name");
id := std_cfg.p_id;
check(id = get_id("provider:vc_name:" & to_string(instance)));
check(std_cfg.p_actor = find(id, enable_deferred_creation => false));
check(std_cfg.p_logger = get_logger(id));
check(get_logger(std_cfg.p_checker) = get_logger(id));
check(std_cfg.p_unexpected_msg_type_policy = fail);
end loop;

elsif run("Test standard config with specified unexpected message type policy") then
std_cfg := create_std_cfg(
provider => "provider",
vc_name => "vc_name",
unexpected_msg_type_policy => ignore
);
id := std_cfg.p_id;
check(id = get_id("provider:vc_name:1"));
check(std_cfg.p_actor = find(id, enable_deferred_creation => false));
check(std_cfg.p_logger = get_logger(id));
check(get_logger(std_cfg.p_checker) = get_logger(id));
check(std_cfg.p_unexpected_msg_type_policy = ignore);

elsif run("Test failing on reused actor") then
mock(vc_pkg_logger, error);
id := get_id("foo:bar");
actor := new_actor(id);
std_cfg := create_std_cfg(id => id);
check_only_log(vc_pkg_logger, "An actor already exists for foo:bar.", error);
unmock(vc_pkg_logger);

elsif run("Test failing on unexpected message") then
id := get_id("id");
std_cfg := create_std_cfg(id => id);
mock(get_logger(id), failure);
unexpected_msg_type(unknown_msg_type, std_cfg);
check_only_log(get_logger(id), "Got unexpected message unknown_msg", failure);
unmock(get_logger(id));

elsif run("Test ignoring unexpected message") then
id := get_id("id");
std_cfg := create_std_cfg(id => id, unexpected_msg_type_policy => ignore);
mock(get_logger(id), failure);
unexpected_msg_type(unknown_msg_type, std_cfg);
check_no_log;
unmock(get_logger(id));

end if;
end loop;
test_runner_cleanup(runner, fail_on_warning => true);
end process;
end architecture;

0 comments on commit 32c821c

Please sign in to comment.