Skip to content

Commit 51365a5

Browse files
committed
Added support package for standard VCs
1 parent c477669 commit 51365a5

File tree

4 files changed

+284
-0
lines changed

4 files changed

+284
-0
lines changed

vunit/vhdl/com/src/com_types.vhd

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -403,6 +403,9 @@ package com_types_pkg is
403403
-- Misc
404404
impure function to_integer(actor : actor_t) return integer;
405405
impure function to_actor(value : integer) return actor_t;
406+
407+
-- Private
408+
impure function is_valid(code : integer) return boolean;
406409
end package;
407410

408411
package body com_types_pkg is

vunit/vhdl/verification_components/src/vc_context.vhd

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ context vc_context is
1919
use vunit_lib.stream_slave_pkg.all;
2020
use vunit_lib.sync_pkg.all;
2121
use vunit_lib.uart_pkg.all;
22+
use vunit_lib.vc_pkg.all;
2223
use vunit_lib.wishbone_pkg.all;
2324
context vunit_lib.com_context;
2425
end context;
Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
-- This Source Code Form is subject to the terms of the Mozilla Public
2+
-- License, v. 2.0. If a copy of the MPL was not distributed with this file,
3+
-- You can obtain one at http://mozilla.org/MPL/2.0/.
4+
--
5+
-- Copyright (c) 2014-2024, Lars Asplund [email protected]
6+
--
7+
-- This package contains common functionality for VCs.
8+
9+
context work.vunit_context;
10+
context work.com_context;
11+
12+
package vc_pkg is
13+
type unexpected_msg_type_policy_t is (fail, ignore);
14+
15+
type std_cfg_t is record
16+
p_data : integer_vector_ptr_t;
17+
end record;
18+
19+
constant null_std_cfg : std_cfg_t := (
20+
p_data => null_integer_vector_ptr
21+
);
22+
23+
-- Creates a standard VC configuration with an id, an actor, a logger, a
24+
-- checker, and an unexpected message type policy.
25+
--
26+
-- If id = null_id, the id will be assigned the name provider:vc_name:n where n is 1
27+
-- for the first instance and increasing with one for every additional instance.
28+
--
29+
-- The id must not have an associated actor before the call as that may indicate
30+
-- several users of the same actor.
31+
--
32+
-- If a logger exist for the id, it will be reused. If not, a new logger is created.
33+
-- A new checker is created that reports to the logger.
34+
impure function create_std_cfg(
35+
id : id_t := null_id;
36+
provider : string := "";
37+
vc_name : string := "";
38+
unexpected_msg_type_policy : unexpected_msg_type_policy_t := fail
39+
) return std_cfg_t;
40+
41+
-- Used to create enumerated ids from a parent id. The first created
42+
-- id will be <parent name>:1, the second <parent name>:2 and so on
43+
impure function enumerate(parent : id_t) return id_t;
44+
45+
-- These functions extracts information from the standard VC configuration
46+
impure function get_id(std_cfg : std_cfg_t) return id_t;
47+
impure function get_actor(std_cfg : std_cfg_t) return actor_t;
48+
impure function get_logger(std_cfg : std_cfg_t) return logger_t;
49+
impure function get_checker(std_cfg : std_cfg_t) return checker_t;
50+
impure function unexpected_msg_type_policy(std_cfg : std_cfg_t) return unexpected_msg_type_policy_t;
51+
52+
-- Handle messages with unexpected message type according to the standard configuration
53+
procedure unexpected_msg_type(msg_type : msg_type_t; std_cfg : std_cfg_t);
54+
55+
end package;
56+
57+
package body vc_pkg is
58+
constant vc_pkg_logger : logger_t := get_logger("vunit_lib:vc_pkg");
59+
constant vc_pkg_checker : checker_t := new_checker(vc_pkg_logger);
60+
61+
constant id_idx : natural := 0;
62+
constant actor_idx : natural := 1;
63+
constant logger_idx : natural := 2;
64+
constant checker_idx : natural := 3;
65+
constant unexpected_msg_type_policy_idx : natural := 4;
66+
constant std_cfg_length : natural := unexpected_msg_type_policy_idx + 1;
67+
68+
impure function enumerate(parent : id_t) return id_t is
69+
begin
70+
return get_id(to_string(num_children(parent) + 1), parent => parent);
71+
end;
72+
73+
impure function create_std_cfg(
74+
id : id_t := null_id;
75+
provider : string := "";
76+
vc_name : string := "";
77+
unexpected_msg_type_policy : unexpected_msg_type_policy_t := fail
78+
) return std_cfg_t is
79+
variable std_cfg : std_cfg_t;
80+
variable provider_id : id_t;
81+
variable vc_id : id_t;
82+
variable instance_id : id_t;
83+
variable actor : actor_t;
84+
variable logger : logger_t;
85+
begin
86+
std_cfg.p_data := new_integer_vector_ptr(std_cfg_length);
87+
88+
if id /= null_id then
89+
instance_id := id;
90+
else
91+
if provider = "" then
92+
check_failed(vc_pkg_checker, "A provider must be provided.");
93+
94+
-- Simplifies testing when vc_pkg_checker logger is mocked
95+
return null_std_cfg;
96+
end if;
97+
98+
if vc_name = "" then
99+
check_failed(vc_pkg_checker, "A VC name must be provided.");
100+
101+
-- Simplifies testing when vc_pkg_checker logger is mocked
102+
return null_std_cfg;
103+
end if;
104+
105+
provider_id := get_id(provider);
106+
vc_id := get_id(vc_name, parent => provider_id);
107+
instance_id := enumerate(vc_id);
108+
end if;
109+
set(std_cfg.p_data, id_idx, to_integer(instance_id));
110+
111+
if find(instance_id, enable_deferred_creation => false) /= null_actor then
112+
check_failed(vc_pkg_checker, "An actor already exists for " & full_name(instance_id) & ".");
113+
114+
-- Simplifies testing when vc_pkg_checker logger is mocked
115+
return null_std_cfg;
116+
else
117+
actor := new_actor(instance_id);
118+
end if;
119+
set(std_cfg.p_data, actor_idx, to_integer(actor));
120+
121+
logger := get_logger(instance_id);
122+
set(std_cfg.p_data, logger_idx, to_integer(logger));
123+
124+
set(std_cfg.p_data, checker_idx, to_integer(new_checker(logger)));
125+
126+
set(
127+
std_cfg.p_data,
128+
unexpected_msg_type_policy_idx,
129+
unexpected_msg_type_policy_t'pos(unexpected_msg_type_policy)
130+
);
131+
132+
return std_cfg;
133+
end;
134+
135+
impure function get_id(std_cfg : std_cfg_t) return id_t is
136+
begin
137+
return to_id(get(std_cfg.p_data, id_idx));
138+
end;
139+
140+
impure function get_actor(std_cfg : std_cfg_t) return actor_t is
141+
begin
142+
return to_actor(get(std_cfg.p_data, actor_idx));
143+
end;
144+
145+
impure function get_logger(std_cfg : std_cfg_t) return logger_t is
146+
begin
147+
return to_logger(get(std_cfg.p_data, logger_idx));
148+
end;
149+
150+
impure function get_checker(std_cfg : std_cfg_t) return checker_t is
151+
begin
152+
return to_checker(get(std_cfg.p_data, checker_idx));
153+
end;
154+
155+
impure function unexpected_msg_type_policy(std_cfg : std_cfg_t) return unexpected_msg_type_policy_t is
156+
begin
157+
return unexpected_msg_type_policy_t'val(get(std_cfg.p_data, unexpected_msg_type_policy_idx));
158+
end;
159+
160+
procedure unexpected_msg_type(msg_type : msg_type_t;
161+
std_cfg : std_cfg_t) is
162+
constant code : integer := msg_type.p_code;
163+
begin
164+
if is_already_handled(msg_type) or unexpected_msg_type_policy(std_cfg) = ignore then
165+
null;
166+
elsif is_valid(code) then
167+
check_failed(
168+
get_checker(std_cfg),
169+
"Got unexpected message " & to_string(to_string_ptr(get(p_msg_types.p_name_ptrs, code)))
170+
);
171+
else
172+
check_failed(
173+
get_checker(std_cfg),
174+
"Got invalid message with code " & to_string(code)
175+
);
176+
end if;
177+
end procedure;
178+
end package body;
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
-- This Source Code Form is subject to the terms of the Mozilla Public
2+
-- License, v. 2.0. If a copy of the MPL was not distributed with this file,
3+
-- You can obtain one at http://mozilla.org/MPL/2.0/.
4+
--
5+
-- Copyright (c) 2014-2024, Lars Asplund [email protected]
6+
7+
library vunit_lib;
8+
context vunit_lib.vunit_context;
9+
context work.com_context;
10+
use work.vc_pkg.all;
11+
12+
entity tb_vc_pkg is
13+
generic(runner_cfg : string);
14+
end entity;
15+
16+
architecture a of tb_vc_pkg is
17+
begin
18+
19+
main : process
20+
variable std_cfg : std_cfg_t;
21+
variable id : id_t;
22+
variable actor : actor_t;
23+
24+
constant vc_pkg_logger : logger_t := get_logger("vunit_lib:vc_pkg");
25+
constant unknown_msg_type : msg_type_t := new_msg_type("unknown_msg");
26+
begin
27+
test_runner_setup(runner, runner_cfg);
28+
while test_suite loop
29+
if run("Test that provider must be supplied with null_id") then
30+
mock(vc_pkg_logger, error);
31+
std_cfg := create_std_cfg(vc_name => "my_vc");
32+
check_only_log(vc_pkg_logger, "A provider must be provided.", error);
33+
unmock(vc_pkg_logger);
34+
35+
elsif run("Test that vc_name must be supplied with null_id") then
36+
mock(vc_pkg_logger, error);
37+
std_cfg := create_std_cfg(provider => "provider");
38+
check_only_log(vc_pkg_logger, "A VC name must be provided.", error);
39+
unmock(vc_pkg_logger);
40+
41+
elsif run("Test standard config with specified id") then
42+
id := get_id("id");
43+
std_cfg := create_std_cfg(id => id);
44+
check(get_id(std_cfg) = id);
45+
check(get_actor(std_cfg) = find(id, enable_deferred_creation => false));
46+
check(get_logger(std_cfg) = get_logger(id));
47+
check(get_logger(get_checker(std_cfg)) = get_logger(id));
48+
check(unexpected_msg_type_policy(std_cfg) = fail);
49+
50+
elsif run("Test standard config with null_id") then
51+
for instance in 1 to 3 loop
52+
std_cfg := create_std_cfg(provider => "provider", vc_name => "vc_name");
53+
id := get_id(std_cfg);
54+
check(id = get_id("provider:vc_name:" & to_string(instance)));
55+
check(get_actor(std_cfg) = find(id, enable_deferred_creation => false));
56+
check(get_logger(std_cfg) = get_logger(id));
57+
check(get_logger(get_checker(std_cfg)) = get_logger(id));
58+
check(unexpected_msg_type_policy(std_cfg) = fail);
59+
end loop;
60+
61+
elsif run("Test standard config with specified unexpected message type policy") then
62+
std_cfg := create_std_cfg(
63+
provider => "provider",
64+
vc_name => "vc_name",
65+
unexpected_msg_type_policy => ignore
66+
);
67+
id := get_id(std_cfg);
68+
check(id = get_id("provider:vc_name:1"));
69+
check(get_actor(std_cfg) = find(id, enable_deferred_creation => false));
70+
check(get_logger(std_cfg) = get_logger(id));
71+
check(get_logger(get_checker(std_cfg)) = get_logger(id));
72+
check(unexpected_msg_type_policy(std_cfg) = ignore);
73+
74+
elsif run("Test failing on reused actor") then
75+
mock(vc_pkg_logger, error);
76+
id := get_id("foo:bar");
77+
actor := new_actor(id);
78+
std_cfg := create_std_cfg(id => id);
79+
check_only_log(vc_pkg_logger, "An actor already exists for foo:bar.", error);
80+
unmock(vc_pkg_logger);
81+
82+
elsif run("Test failing on unexpected message") then
83+
id := get_id("id");
84+
std_cfg := create_std_cfg(id => id);
85+
mock(get_logger(id), error);
86+
unexpected_msg_type(unknown_msg_type, std_cfg);
87+
check_only_log(get_logger(id), "Got unexpected message unknown_msg", error);
88+
unmock(get_logger(id));
89+
90+
elsif run("Test ignoring unexpected message") then
91+
id := get_id("id");
92+
std_cfg := create_std_cfg(id => id, unexpected_msg_type_policy => ignore);
93+
mock(get_logger(id), error);
94+
unexpected_msg_type(unknown_msg_type, std_cfg);
95+
check_no_log;
96+
unmock(get_logger(id));
97+
98+
end if;
99+
end loop;
100+
test_runner_cleanup(runner, fail_on_warning => true);
101+
end process;
102+
end architecture;

0 commit comments

Comments
 (0)