EDA Playground lets you type in and run HDL code (using a selection of free and commercial simulators and synthesizers).
It's great for learning HDLs, it's great for testing out unfamiliar things and it's great for sharing code.
You can start typing straight away. But to run your code, you'll need to sign or log in. Logging in with a Google account gives you access to all non-commercial simulators and some commercial simulators:
To run commercial simulators, you need to register and log in with a username and password. Registration is free, and only pre-approved email's will have access to the commercial simulators.
206
--========================================================================================================================
-- Copyright (c) 2017 by Bitvis AS. All rights reserved.
-- You should have received a copy of the license file containing the MIT License (see LICENSE.TXT), if not,
-- contact Bitvis AS <support@bitvis.no>.
--
-- UVVM AND ANY PART THEREOF ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
-- WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
-- OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-- OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH UVVM OR THE USE OR OTHER DEALINGS IN UVVM.
--========================================================================================================================
------------------------------------------------------------------------------------------
-- Description : See library quick reference (under 'doc') and README-file(s)
------------------------------------------------------------------------------------------
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
library uvvm_util;
context uvvm_util.uvvm_util_context;
library uvvm_vvc_framework;
use uvvm_vvc_framework.ti_vvc_framework_support_pkg.all;
--library vip_counter;
use work.vvc_methods_pkg.all;
use work.td_vvc_framework_common_methods_pkg.all;
use std.textio.all;
-- Test bench entity
entity counter_vvc_tb is
end entity;
-- Test bench architecture
architecture func of counter_vvc_tb is
constant C_SCOPE : string := C_TB_SCOPE_DEFAULT;
-- Clock and bit period settings
constant C_CLK_PERIOD : time := 10 ns;
constant C_BIT_PERIOD : time := 16 * C_CLK_PERIOD;
begin
-----------------------------------------------------------------------------
-- Instantiate test harness, containing DUT and Executors
-----------------------------------------------------------------------------
i_test_harness : entity work.counter_vvc_th;
------------------------------------------------
-- PROCESS: p_main
------------------------------------------------
p_main: process
variable L : line;
begin
-- Wait for UVVM to finish initialization
await_uvvm_initialization(VOID);
-- TO DO: redirect all messages to a file and the screen
-- TO DO: output the section headers, any message from here and messages related to sending commands to a VVC
-- TO DO: output messages with ID ID_BFM and messages related to the testbench terminating (for whatever reason)
-- IYHT: increase the ERROR stop limit
-- TO DO: display which IDs are enabled or disabled
-- IYHT: display the stop limits
log(ID_LOG_HDR, "Starting simulation of TB for counter using VVCs", C_SCOPE);
------------------------------------------------------------
log(ID_SEQUENCER, "Wait 10 clock period for reset to be turned off", C_SCOPE);
wait for (10 * C_CLK_PERIOD); -- for reset to be turned off
-- ANSWER: write your test case here
-----------------------------------------------------------------------------
-- Ending the simulation
-----------------------------------------------------------------------------
wait for 10 ns; -- to allow some time for completion
report_alert_counters(FINAL); -- Report final counters and print conclusion for simulation (Success/Fail)
log(ID_LOG_HDR, "SIMULATION COMPLETED", C_SCOPE);
-- Finish the simulation
std.env.stop;
wait; -- to stop completely
end process p_main;
end func;
xxxxxxxxxx
--========================================================================================================================
-- This VVC was generated with Bitvis VVC Generator
--========================================================================================================================
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library uvvm_util;
context uvvm_util.uvvm_util_context;
--========================================================================================================================
--========================================================================================================================
package counter_bfm_pkg is
--========================================================================================================================
-- Types and constants for COUNTER BFM
--========================================================================================================================
constant C_SCOPE : string := "COUNTER BFM";
-- Optional interface record for BFM signals
type t_counter_if is record
--<USER_INPUT> Insert all BFM signals here
Reset : std_logic; -- to dut
Enable : std_logic; -- to dut
Load : std_logic; -- to dut
UpDn : std_logic; -- to dut
Data : std_logic_vector; -- to dut
Q : std_logic_vector; -- from dut
end record;
-- Configuration record to be assigned in the test harness.
type t_counter_bfm_config is
record
--<USER_INPUT> Insert all BFM config parameters here
-- Example:
-- max_wait_cycles : integer;
-- max_wait_cycles_severity : t_alert_level;
id_for_bfm : t_msg_id;
-- id_for_bfm_wait : t_msg_id;
-- id_for_bfm_poll : t_msg_id;
clock_period : time; -- Needed in the VVC
end record;
-- Define the default value for the BFM config
constant C_COUNTER_BFM_CONFIG_DEFAULT : t_counter_bfm_config := (
--<USER_INPUT> Insert defaults for all BFM config parameters here
-- Example:
-- max_wait_cycles => 10,
-- max_wait_cycles_severity => failure,
id_for_bfm => ID_BFM,
-- id_for_bfm_wait => ID_BFM_WAIT,
-- id_for_bfm_poll => ID_BFM_POLL,
clock_period => 5 ns
);
--========================================================================================================================
-- BFM procedures
--========================================================================================================================
--<USER_INPUT> Insert BFM procedure declarations here, e.g. read and write operations
-- It is recommended to also have an init function which sets the BFM signals to their default state
------------------------------------------
-- init_counter_if_signals
------------------------------------------
-- - This function returns an SBI interface with initialized signals.
-- - All counter input signals are initialized to 0
-- - All counter outut signals are initialized to Z
function init_counter_if_signals(
data_width : natural
) return t_counter_if;
------------------------------------------
-- counter_reset
------------------------------------------
-- - This procedure resets the counter DUT
-- - The counter interface in this procedure is given as individual signals
procedure counter_reset (
constant msg : in string;
signal clk : in std_logic;
signal Reset : out std_logic;
signal Enable : out std_logic;
signal Load : out std_logic;
signal UpDn : out std_logic;
signal Data : out std_logic_vector;
signal Q : inout std_logic_vector;
constant scope : in string := C_SCOPE;
constant msg_id_panel : in t_msg_id_panel := shared_msg_id_panel;
constant config : in t_counter_bfm_config := C_COUNTER_BFM_CONFIG_DEFAULT
);
procedure counter_reset (
constant msg : in string;
signal clk : in std_logic;
signal counter_if : inout t_counter_if;
constant scope : in string := C_SCOPE;
constant msg_id_panel : in t_msg_id_panel := shared_msg_id_panel;
constant config : in t_counter_bfm_config := C_COUNTER_BFM_CONFIG_DEFAULT
);
------------------------------------------
-- counter_check
------------------------------------------
-- - This procedure checks the counter DUT Q output
-- - The counter interface in this procedure is given as individual signals
procedure counter_check (
constant Q_exp : in std_logic_vector;
constant msg : in string;
signal clk : in std_logic;
signal Reset : out std_logic;
signal Enable : out std_logic;
signal Load : out std_logic;
signal UpDn : out std_logic;
signal Data : out std_logic_vector;
signal Q : inout std_logic_vector;
constant alert_level : in t_alert_level := error;
constant scope : in string := C_SCOPE;
constant msg_id_panel : in t_msg_id_panel := shared_msg_id_panel;
constant config : in t_counter_bfm_config := C_COUNTER_BFM_CONFIG_DEFAULT
);
procedure counter_check (
constant Q_exp : in std_logic_vector;
constant msg : in string;
signal clk : in std_logic;
signal counter_if : inout t_counter_if;
constant alert_level : in t_alert_level := error;
constant scope : in string := C_SCOPE;
constant msg_id_panel : in t_msg_id_panel := shared_msg_id_panel;
constant config : in t_counter_bfm_config := C_COUNTER_BFM_CONFIG_DEFAULT
);
------------------------------------------
-- counter_load
------------------------------------------
-- - This procedure loads the counter DUT
-- - The counter interface in this procedure is given as individual signals
procedure counter_load (
constant data_value : in std_logic_vector;
constant msg : in string;
signal clk : in std_logic;
signal Reset : out std_logic;
signal Enable : out std_logic;
signal Load : out std_logic;
signal UpDn : out std_logic;
signal Data : inout std_logic_vector;
signal Q : inout std_logic_vector;
constant scope : in string := C_SCOPE;
constant msg_id_panel : in t_msg_id_panel := shared_msg_id_panel;
constant config : in t_counter_bfm_config := C_COUNTER_BFM_CONFIG_DEFAULT
);
procedure counter_load (
constant data_value : in std_logic_vector;
constant msg : in string;
signal clk : in std_logic;
signal counter_if : inout t_counter_if;
constant scope : in string := C_SCOPE;
constant msg_id_panel : in t_msg_id_panel := shared_msg_id_panel;
constant config : in t_counter_bfm_config := C_COUNTER_BFM_CONFIG_DEFAULT
);
------------------------------------------
-- counter_count_up
------------------------------------------
-- - This procedure makes the counter DUT count up
-- - The counter interface in this procedure is given as individual signals
procedure counter_count_up (
constant cycles : in natural;
constant msg : in string;
signal clk : in std_logic;
signal Reset : out std_logic;
signal Enable : out std_logic;
signal Load : out std_logic;
signal UpDn : out std_logic;
signal Data : out std_logic_vector;
signal Q : inout std_logic_vector;
constant scope : in string := C_SCOPE;
constant msg_id_panel : in t_msg_id_panel := shared_msg_id_panel;
constant config : in t_counter_bfm_config := C_COUNTER_BFM_CONFIG_DEFAULT
);
procedure counter_count_up (
constant cycles : in natural;
constant msg : in string;
signal clk : in std_logic;
signal counter_if : inout t_counter_if;
constant scope : in string := C_SCOPE;
constant msg_id_panel : in t_msg_id_panel := shared_msg_id_panel;
constant config : in t_counter_bfm_config := C_COUNTER_BFM_CONFIG_DEFAULT
);
-- IYHT: check counting down
------------------------------------------
-- counter_hold
------------------------------------------
-- - This procedure makes the counter DUT hold
-- - The counter interface in this procedure is given as individual signals
procedure counter_hold (
constant cycles : in natural;
constant msg : in string;
signal clk : in std_logic;
signal Reset : out std_logic;
signal Enable : out std_logic;
signal Load : out std_logic;
signal UpDn : out std_logic;
signal Data : out std_logic_vector;
signal Q : inout std_logic_vector;
constant scope : in string := C_SCOPE;
constant msg_id_panel : in t_msg_id_panel := shared_msg_id_panel;
constant config : in t_counter_bfm_config := C_COUNTER_BFM_CONFIG_DEFAULT
);
procedure counter_hold (
constant cycles : in natural;
constant msg : in string;
signal clk : in std_logic;
signal counter_if : inout t_counter_if;
constant scope : in string := C_SCOPE;
constant msg_id_panel : in t_msg_id_panel := shared_msg_id_panel;
constant config : in t_counter_bfm_config := C_COUNTER_BFM_CONFIG_DEFAULT
);
end package counter_bfm_pkg;
--========================================================================================================================
--========================================================================================================================
package body counter_bfm_pkg is
--<USER_INPUT> Insert BFM procedure implementation here.
------------------------------------------
-- init_counter_if_signals
------------------------------------------
-- - This function returns an SBI interface with initialized signals.
-- - All counter input signals are initialized to 0
-- - All counter outut signals are initialized to Z
function init_counter_if_signals(
data_width : natural
) return t_counter_if is
variable result : t_counter_if( data(data_width - 1 downto 0),
Q(data_width - 1 downto 0));
begin
result.Reset := '0';
result.Enable := '0';
result.Load := '0';
result.UpDn := '0';
result.Data := (result.Data'range => '0');
result.Q := (result.Q'range => 'Z');
return result;
end function;
------------------------------------------
-- counter_reset
------------------------------------------
-- - This procedure resets the counter DUT
-- - The counter interface in this procedure is given as individual signals
procedure counter_reset (
constant msg : in string;
signal clk : in std_logic;
signal Reset : out std_logic;
signal Enable : out std_logic;
signal Load : out std_logic;
signal UpDn : out std_logic;
signal Data : out std_logic_vector;
signal Q : inout std_logic_vector;
constant scope : in string := C_SCOPE;
constant msg_id_panel : in t_msg_id_panel := shared_msg_id_panel;
constant config : in t_counter_bfm_config := C_COUNTER_BFM_CONFIG_DEFAULT
) is
constant proc_name : string := "counter_reset";
constant proc_call : string := "counter_reset()";
begin
wait_num_rising_edge(clk, 1);
Reset <= '1';
wait_num_rising_edge(clk, 1);
Reset <= '0';
log(config.id_for_bfm, proc_call & " completed. " & add_msg_delimiter(msg), scope, msg_id_panel);
end procedure;
procedure counter_reset (
constant msg : in string;
signal clk : in std_logic;
signal counter_if : inout t_counter_if;
constant scope : in string := C_SCOPE;
constant msg_id_panel : in t_msg_id_panel := shared_msg_id_panel;
constant config : in t_counter_bfm_config := C_COUNTER_BFM_CONFIG_DEFAULT
) is
begin
counter_reset ( msg,
clk,
counter_if.Reset,
counter_if.Enable,
counter_if.Load,
counter_if.UpDn,
counter_if.Data,
counter_if.Q,
scope,
msg_id_panel,
config);
end procedure;
------------------------------------------
-- counter_check
------------------------------------------
-- - This procedure checks the counter DUT Q output
-- - The counter interface in this procedure is given as individual signals
procedure counter_check (
constant Q_exp : in std_logic_vector;
constant msg : in string;
signal clk : in std_logic;
signal Reset : out std_logic;
signal Enable : out std_logic;
signal Load : out std_logic;
signal UpDn : out std_logic;
signal Data : out std_logic_vector;
signal Q : inout std_logic_vector;
constant alert_level : in t_alert_level := error;
constant scope : in string := C_SCOPE;
constant msg_id_panel : in t_msg_id_panel := shared_msg_id_panel;
constant config : in t_counter_bfm_config := C_COUNTER_BFM_CONFIG_DEFAULT
) is
constant proc_name : string := "counter_check";
constant proc_call : string := "counter_check(Q_exp:" & to_string(Q_exp, HEX, AS_IS, INCL_RADIX) & ")";
variable v_check_ok : boolean;
-- Normalise to the DUT Q width
variable v_normalised_Q : std_logic_vector(Q'length-1 downto 0) :=
normalize_and_check(Q_exp, Q, ALLOW_EXACT_ONLY, "Q_exp", "counter_core_in.Q", msg);
begin
v_check_ok := check_value(Q, Q_exp, alert_level, msg, scope, HEX_BIN_IF_INVALID, SKIP_LEADING_0, ID_NEVER, msg_id_panel, proc_call);
if v_check_ok then
log(config.id_for_bfm, proc_call & "=> OK, Q = " & to_string(Q_exp, HEX, SKIP_LEADING_0, INCL_RADIX) & ". " & add_msg_delimiter(msg), scope, msg_id_panel);
end if;
end procedure;
procedure counter_check (
constant Q_exp : in std_logic_vector;
constant msg : in string;
signal clk : in std_logic;
signal counter_if : inout t_counter_if;
constant alert_level : in t_alert_level := error;
constant scope : in string := C_SCOPE;
constant msg_id_panel : in t_msg_id_panel := shared_msg_id_panel;
constant config : in t_counter_bfm_config := C_COUNTER_BFM_CONFIG_DEFAULT
) is
begin
counter_check ( Q_exp,
msg,
clk,
counter_if.Reset,
counter_if.Enable,
counter_if.Load,
counter_if.UpDn,
counter_if.Data,
counter_if.Q,
alert_level,
scope,
msg_id_panel,
config);
end procedure;
------------------------------------------
-- counter_load
------------------------------------------
-- - This procedure loads the counter DUT
-- - The counter interface in this procedure is given as individual signals
procedure counter_load (
constant data_value : in std_logic_vector;
constant msg : in string;
signal clk : in std_logic;
signal Reset : out std_logic;
signal Enable : out std_logic;
signal Load : out std_logic;
signal UpDn : out std_logic;
signal Data : inout std_logic_vector;
signal Q : inout std_logic_vector;
constant scope : in string := C_SCOPE;
constant msg_id_panel : in t_msg_id_panel := shared_msg_id_panel;
constant config : in t_counter_bfm_config := C_COUNTER_BFM_CONFIG_DEFAULT
) is
constant proc_name : string := "counter_load";
constant proc_call : string := "counter_load(data_value:" & to_string(data_value, HEX, AS_IS, INCL_RADIX) & ")";
-- Normalise to the DUT data_value width
variable v_normalised_data : std_logic_vector(Data'length-1 downto 0) :=
normalize_and_check(data_value, Data, ALLOW_EXACT_ONLY, "data_value", "counter_core_in.Data", msg);
begin
wait_num_rising_edge(clk, 1);
Enable <= '1';
Load <= '1';
Data <= v_normalised_data;
wait_num_rising_edge(clk, 1);
Load <= '0';
log(config.id_for_bfm, proc_call & " completed. " & add_msg_delimiter(msg), scope, msg_id_panel);
end procedure;
procedure counter_load (
constant data_value : in std_logic_vector;
constant msg : in string;
signal clk : in std_logic;
signal counter_if : inout t_counter_if;
constant scope : in string := C_SCOPE;
constant msg_id_panel : in t_msg_id_panel := shared_msg_id_panel;
constant config : in t_counter_bfm_config := C_COUNTER_BFM_CONFIG_DEFAULT
) is
begin
counter_load ( data_value,
msg,
clk,
counter_if.Reset,
counter_if.Enable,
counter_if.Load,
counter_if.UpDn,
counter_if.Data,
counter_if.Q,
scope,
msg_id_panel,
config);
end procedure;
------------------------------------------
-- counter_count_up
------------------------------------------
-- - This procedure makes the counter DUT count up
-- - The counter interface in this procedure is given as individual signals
procedure counter_count_up (
constant cycles : in natural;
constant msg : in string;
signal clk : in std_logic;
signal Reset : out std_logic;
signal Enable : out std_logic;
signal Load : out std_logic;
signal UpDn : out std_logic;
signal Data : out std_logic_vector;
signal Q : inout std_logic_vector;
constant scope : in string := C_SCOPE;
constant msg_id_panel : in t_msg_id_panel := shared_msg_id_panel;
constant config : in t_counter_bfm_config := C_COUNTER_BFM_CONFIG_DEFAULT
) is
use std.textio.side;
constant proc_name : string := "counter_count_up";
constant proc_call : string := "counter_count_up(cycles:" & integer'image(cycles) & ")";
-- Normalise to the DUT data_value width
begin
Enable <= '1';
UpDn <= '1';
Load <= '0';
wait_num_rising_edge(clk, cycles);
log(config.id_for_bfm, proc_call & " completed. " & add_msg_delimiter(msg), scope, msg_id_panel);
end procedure;
procedure counter_count_up (
constant cycles : in natural;
constant msg : in string;
signal clk : in std_logic;
signal counter_if : inout t_counter_if;
constant scope : in string := C_SCOPE;
constant msg_id_panel : in t_msg_id_panel := shared_msg_id_panel;
constant config : in t_counter_bfm_config := C_COUNTER_BFM_CONFIG_DEFAULT
) is
begin
counter_count_up ( cycles,
msg,
clk,
counter_if.Reset,
counter_if.Enable,
counter_if.Load,
counter_if.UpDn,
counter_if.Data,
counter_if.Q,
scope,
msg_id_panel,
config);
end procedure;
-- IYHT: check counting down
------------------------------------------
-- counter_hold
------------------------------------------
-- - This procedure makes the counter DUT hold
-- - The counter interface in this procedure is given as individual signals
procedure counter_hold (
constant cycles : in natural;
constant msg : in string;
signal clk : in std_logic;
signal Reset : out std_logic;
signal Enable : out std_logic;
signal Load : out std_logic;
signal UpDn : out std_logic;
signal Data : out std_logic_vector;
signal Q : inout std_logic_vector;
constant scope : in string := C_SCOPE;
constant msg_id_panel : in t_msg_id_panel := shared_msg_id_panel;
constant config : in t_counter_bfm_config := C_COUNTER_BFM_CONFIG_DEFAULT
) is
use std.textio.side;
constant proc_name : string := "counter_hold";
constant proc_call : string := "counter_hold(cycles:" & integer'image(cycles) & ")";
-- Normalise to the DUT data_value width
begin
Enable <= '0';
wait_num_rising_edge(clk, cycles);
log(config.id_for_bfm, proc_call & " completed. " & add_msg_delimiter(msg), scope, msg_id_panel);
end procedure;
procedure counter_hold (
constant cycles : in natural;
constant msg : in string;
signal clk : in std_logic;
signal counter_if : inout t_counter_if;
constant scope : in string := C_SCOPE;
constant msg_id_panel : in t_msg_id_panel := shared_msg_id_panel;
constant config : in t_counter_bfm_config := C_COUNTER_BFM_CONFIG_DEFAULT
) is
begin
counter_hold ( cycles,
msg,
clk,
counter_if.Reset,
counter_if.Enable,
counter_if.Load,
counter_if.UpDn,
counter_if.Data,
counter_if.Q,
scope,
msg_id_panel,
config);
end procedure;
end package body counter_bfm_pkg;
xxxxxxxxxx
--========================================================================================================================
-- This VVC was generated with Bitvis VVC Generator
--========================================================================================================================
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library uvvm_util;
context uvvm_util.uvvm_util_context;
library uvvm_vvc_framework;
use uvvm_vvc_framework.ti_vvc_framework_support_pkg.all;
--========================================================================================================================
--========================================================================================================================
package vvc_cmd_pkg is
--========================================================================================================================
-- t_operation
-- - VVC and BFM operations
--========================================================================================================================
type t_operation is (
NO_OPERATION,
AWAIT_COMPLETION,
AWAIT_ANY_COMPLETION,
ENABLE_LOG_MSG,
DISABLE_LOG_MSG,
FLUSH_COMMAND_QUEUE,
FETCH_RESULT,
INSERT_DELAY,
TERMINATE_CURRENT_COMMAND,
--<USER_INPUT> Expand this type with enums for BFM procedures.
RESET, LOAD, CHECK, COUNT_UP, HOLD
); -- IYHT: check counting down
--<USER_INPUT> Create constants for the maximum sizes to use in this VVC.
-- You can create VVCs with smaller sizes than these constants, but not larger.
-- For example, given a VVC with parallel data bus and address bus, constraints should be added for maximum data length
-- and address length
-- Example:
constant C_VVC_CMD_DATA_MAX_LENGTH : natural := 8;
-- constant C_VVC_CMD_ADDR_MAX_LENGTH : natural := 8;
constant C_VVC_CMD_STRING_MAX_LENGTH : natural := 300;
--========================================================================================================================
-- t_vvc_cmd_record
-- - Record type used for communication with the VVC
--========================================================================================================================
type t_vvc_cmd_record is record
-- VVC dedicated fields
--<USER_INPUT> Insert all data types needed to transport data to the BFM here.
-- This includes data field, address field, constraints (e.g. timeout), etc.
data : std_logic_vector(C_VVC_CMD_DATA_MAX_LENGTH-1 downto 0);
Q : std_logic_vector(C_VVC_CMD_DATA_MAX_LENGTH-1 downto 0);
cycles : natural;
-- Common VVC fields
operation : t_operation;
proc_call : string(1 to C_VVC_CMD_STRING_MAX_LENGTH);
msg : string(1 to C_VVC_CMD_STRING_MAX_LENGTH);
cmd_idx : natural;
command_type : t_immediate_or_queued;
msg_id : t_msg_id;
gen_integer_array : t_integer_array(0 to 1); -- Increase array length if needed
gen_boolean : boolean; -- Generic boolean
timeout : time;
alert_level : t_alert_level;
delay : time;
quietness : t_quietness;
end record;
constant C_VVC_CMD_DEFAULT : t_vvc_cmd_record := (
--<USER_INPUT> Set the fields you added to the t_vvc_cmd_record above to their default value here
data => (others => '0'),
Q => (others => '0'),
cycles => 1,
-- Common VVC fields
operation => NO_OPERATION,
proc_call => (others => NUL),
msg => (others => NUL),
cmd_idx => 0,
command_type => NO_COMMAND_TYPE,
msg_id => NO_ID,
gen_integer_array => (others => -1),
gen_boolean => false,
timeout => 0 ns,
alert_level => FAILURE,
delay => 0 ns,
quietness => NON_QUIET
);
--========================================================================================================================
-- shared_vvc_cmd
-- - Shared variable used for transmitting VVC commands
--========================================================================================================================
shared variable shared_vvc_cmd : t_vvc_cmd_record := C_VVC_CMD_DEFAULT;
--========================================================================================================================
-- t_vvc_result, t_vvc_result_queue_element, t_vvc_response and shared_vvc_response :
--
-- - Used for storing the result of a BFM procedure called by the VVC,
-- so that the result can be transported from the VVC to for example a sequencer via
-- fetch_result() as described in VVC_Framework_common_methods_QuickRef
--
-- - t_vvc_result includes the return value of the procedure in the BFM.
-- It can also be defined as a record if multiple values shall be transported from the BFM
--========================================================================================================================
subtype t_vvc_result is std_logic_vector(C_VVC_CMD_DATA_MAX_LENGTH-1 downto 0);
type t_vvc_result_queue_element is record
cmd_idx : natural; -- from UVVM handshake mechanism
result : t_vvc_result;
end record;
type t_vvc_response is record
fetch_is_accepted : boolean;
transaction_result : t_transaction_result;
result : t_vvc_result;
end record;
shared variable shared_vvc_response : t_vvc_response;
--========================================================================================================================
-- t_last_received_cmd_idx :
-- - Used to store the last queued cmd in vvc interpreter.
--========================================================================================================================
type t_last_received_cmd_idx is array (t_channel range <>,natural range <>) of integer;
--========================================================================================================================
-- shared_vvc_last_received_cmd_idx
-- - Shared variable used to get last queued index from vvc to sequencer
--========================================================================================================================
shared variable shared_vvc_last_received_cmd_idx : t_last_received_cmd_idx(t_channel'left to t_channel'right, 0 to C_MAX_VVC_INSTANCE_NUM) := (others => (others => -1));
end package vvc_cmd_pkg;
package body vvc_cmd_pkg is
end package body vvc_cmd_pkg;
xxxxxxxxxx
--========================================================================================================================
-- Copyright (c) 2017 by Bitvis AS. All rights reserved.
-- You should have received a copy of the license file containing the MIT License (see LICENSE.TXT), if not,
-- contact Bitvis AS <support@bitvis.no>.
--
-- UVVM AND ANY PART THEREOF ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
-- WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
-- OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-- OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH UVVM OR THE USE OR OTHER DEALINGS IN UVVM.
--========================================================================================================================
------------------------------------------------------------------------------------------
-- Description : See library quick reference (under 'doc') and README-file(s)
------------------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use std.textio.all;
library uvvm_util;
context uvvm_util.uvvm_util_context;
library uvvm_vvc_framework;
use uvvm_vvc_framework.ti_vvc_framework_support_pkg.all;
use work.vvc_cmd_pkg.all;
package td_target_support_pkg is
signal global_vvc_ack : std_logic; -- ACK on global triggers
signal global_vvc_busy : std_logic := 'L'; -- ACK on global triggers
shared variable protected_multicast_semaphore : t_protected_semaphore;
shared variable protected_acknowledge_index : t_protected_acknowledge_cmd_idx;
type t_vvc_target_record_unresolved is record -- VVC dedicated to assure signature differences between equal common methods
trigger : std_logic;
vvc_name : string(1 to C_LOG_SCOPE_WIDTH-2); -- as scope is vvc_name & ',' and number
vvc_instance_idx : integer;
vvc_channel : t_channel;
end record;
constant C_VVC_TARGET_RECORD_DEFAULT : t_vvc_target_record_unresolved := (
trigger => 'L',
vvc_name => (others => '?'),
vvc_instance_idx => -1,
vvc_channel => NA
); --
type t_vvc_target_record_drivers is array (natural range <> ) of t_vvc_target_record_unresolved;
function resolved ( input_vector : t_vvc_target_record_drivers) return t_vvc_target_record_unresolved;
subtype t_vvc_target_record is resolved t_vvc_target_record_unresolved;
-------------------------------------------
-- to_string
-------------------------------------------
-- to_string method for VVC name, instance and channel
-- - If channel is set to NA, it will not be included in the string
function to_string(
value : t_vvc_target_record;
vvc_instance : integer := -1;
vvc_channel : t_channel := NA
) return string;
-------------------------------------------
-- format_command_idx
-------------------------------------------
-- Returns an encapsulated command index as string
impure function format_command_idx(
command : t_vvc_cmd_record -- VVC dedicated
) return string;
-------------------------------------------
-- send_command_to_vvc
-------------------------------------------
-- Sends command to VVC and waits for ACK or timeout
-- - Logs with ID_UVVM_SEND_CMD when sending to VVC
-- - Logs with ID_UVVM_CMD_ACK when ACK or timeout occurs
procedure send_command_to_vvc( -- VVC dedicated shared command used shared_vvc_cmd
signal vvc_target : inout t_vvc_target_record;
constant timeout : in time := std.env.resolution_limit
);
-------------------------------------------
-- set_vvc_target_defaults
-------------------------------------------
-- Returns a vvc target record with vvc_name and values specified in C_VVC_TARGET_RECORD_DEFAULT
function set_vvc_target_defaults (
constant vvc_name : in string
) return t_vvc_target_record;
-------------------------------------------
-- set_general_target_and_command_fields
-------------------------------------------
-- Sets target index and channel, and updates shared_vvc_cmd
procedure set_general_target_and_command_fields ( -- VVC dedicated shared command used shared_vvc_cmd
signal target : inout t_vvc_target_record;
constant vvc_instance_idx : in integer;
constant proc_call : in string;
constant msg : in string;
constant command_type : in t_immediate_or_queued;
constant operation : in t_operation
);
-------------------------------------------
-- set_general_target_and_command_fields
-------------------------------------------
-- Sets target index and channel, and updates shared_vvc_cmd
procedure set_general_target_and_command_fields ( -- VVC dedicated shared command used shared_vvc_cmd
signal target : inout t_vvc_target_record;
constant vvc_instance_idx : in integer;
constant vvc_channel : in t_channel;
constant proc_call : in string;
constant msg : in string;
constant command_type : in t_immediate_or_queued;
constant operation : in t_operation
);
-------------------------------------------
-- acknowledge_cmd
-------------------------------------------
-- Drives global_vvc_ack signal (to '1') for 1 delta cycle, then sets it back to 'Z'.
procedure acknowledge_cmd (
signal vvc_ack : inout std_logic;
constant command_idx : in natural
);
end package td_target_support_pkg;
package body td_target_support_pkg is
function resolved ( input_vector : t_vvc_target_record_drivers) return t_vvc_target_record_unresolved is
-- if none of the drives want to drive the target return value of first driver (which we need to drive at least the target name)
constant C_LINE_LENGTH_MAX : natural := 100; -- VVC idx list string length
variable v_result : t_vvc_target_record_unresolved := input_vector(input_vector'low);
variable v_cnt : integer := 0;
variable v_instance_string : string(1 to C_LINE_LENGTH_MAX) := (others => NUL);
variable v_line : line;
variable v_width : integer := 0;
begin
if input_vector'length = 1 then
return input_vector(input_vector'low);
else
for i in input_vector'range loop
-- The VVC is used if instance_idx is not -1 (which is the default value)
if input_vector(i).vvc_instance_idx /= -1 then
-- count the number of sequencer trying to access the VVC
v_cnt := v_cnt + 1;
v_result := input_vector(i);
-- generating string with all instance_idx for report in case of failure
write(v_line, string'(" "));
write(v_line, input_vector(i).vvc_instance_idx);
-- Ensure there is room for the last item and dots
v_width := v_line'length;
if v_width > (C_LINE_LENGTH_MAX-15) then
write(v_line, string'("..."));
exit;
end if;
end if;
end loop;
if v_width > 0 then
v_instance_string(1 to v_width) := v_line.all;
end if;
deallocate(v_line);
check_value(v_cnt < 2, TB_FAILURE, "Arbitration mechanism failed. Check VVC " & to_string(v_result.vvc_name) & " implementation and semaphore handling. Crashing instances with numbers " & v_instance_string(1 to v_width), C_SCOPE, ID_NEVER);
return v_result;
end if;
end resolved;
function to_string(
value : t_vvc_target_record;
vvc_instance : integer := -1;
vvc_channel : t_channel:= NA
) return string is
variable v_instance : integer;
variable v_channel : t_channel;
begin
if vvc_instance = -1 then
v_instance := value.vvc_instance_idx;
else
v_instance := vvc_instance;
end if;
if vvc_channel = NA then
v_channel := value.vvc_channel;
else
v_channel := vvc_channel;
end if;
if v_channel = NA then
return to_string(value.vvc_name) & "," & to_string(v_instance);
else
return to_string(value.vvc_name) & "," & to_string(v_instance) & "," & to_string(v_channel);
end if;
end;
function set_vvc_target_defaults (
constant vvc_name : in string
) return t_vvc_target_record is
variable v_rec : t_vvc_target_record := C_VVC_TARGET_RECORD_DEFAULT;
begin
v_rec.vvc_name := (others => NUL);
v_rec.vvc_name(1 to vvc_name'length) := vvc_name;
return v_rec;
end function;
procedure set_general_target_and_command_fields (
signal target : inout t_vvc_target_record;
constant vvc_instance_idx : in integer;
constant vvc_channel : in t_channel;
constant proc_call : in string;
constant msg : in string;
constant command_type : in t_immediate_or_queued;
constant operation : in t_operation
) is
begin
-- As shared_vvc_cmd is a shared variable we have to get exclusive access to it. Therefor we have to lock the protected_semaphore here.
-- It is unlocked again in await_cmd_from_sequencer after it is copied localy or in send_command_to_vvc if no VVC acknowledges the command.
-- It is guaranteed that no time delay occurs, only delta cycle delay.
await_semaphore_in_delta_cycles(protected_semaphore);
shared_vvc_cmd := C_VVC_CMD_DEFAULT;
target.vvc_instance_idx <= vvc_instance_idx;
target.vvc_channel <= vvc_channel;
shared_vvc_cmd.proc_call := pad_string(proc_call, NUL, shared_vvc_cmd.proc_call'length);
shared_vvc_cmd.msg := (others => NUL); -- default empty
shared_vvc_cmd.msg(1 to msg'length) := msg;
shared_vvc_cmd.command_type := command_type;
shared_vvc_cmd.operation := operation;
end procedure;
procedure set_general_target_and_command_fields (
signal target : inout t_vvc_target_record;
constant vvc_instance_idx : in integer;
constant proc_call : in string;
constant msg : in string;
constant command_type : in t_immediate_or_queued;
constant operation : in t_operation
) is
begin
set_general_target_and_command_fields(target, vvc_instance_idx, NA, proc_call, msg, command_type, operation);
end procedure;
impure function format_command_idx(
command : t_vvc_cmd_record
) return string is
begin
return format_command_idx(command.cmd_idx);
end;
procedure send_command_to_vvc(
signal vvc_target : inout t_vvc_target_record;
constant timeout : in time := std.env.resolution_limit
) is
constant C_SCOPE : string := C_TB_SCOPE_DEFAULT & "(uvvm)";
constant C_CMD_INFO : string := "uvvm cmd " & format_command_idx(shared_cmd_idx+1) & ": ";
variable v_ack_cmd_idx : integer := -1;
variable v_start_time : time;
variable v_local_vvc_cmd : t_vvc_cmd_record;
variable v_local_cmd_idx : integer;
variable v_was_multicast : boolean := false;
begin
check_value((shared_uvvm_state /= IDLE), TB_FAILURE, "UVVM will not work without uvvm_vvc_framework.ti_uvvm_engine instantiated in the test harness", C_SCOPE, ID_NEVER);
-- increment shared_cmd_inx. It is protected by the protected_semaphore and only one sequencer can access the variable at a time.
shared_cmd_idx := shared_cmd_idx + 1;
shared_vvc_cmd.cmd_idx := shared_cmd_idx;
if global_show_msg_for_uvvm_cmd then
log(ID_UVVM_SEND_CMD, to_string(shared_vvc_cmd.proc_call) & ": " & add_msg_delimiter(to_string(shared_vvc_cmd.msg)) & "."
& format_command_idx(shared_cmd_idx), C_SCOPE);
else
log(ID_UVVM_SEND_CMD, to_string(shared_vvc_cmd.proc_call)
& format_command_idx(shared_cmd_idx), C_SCOPE);
end if;
wait for 0 ns;
if (vvc_target.vvc_instance_idx = ALL_INSTANCES) then
await_semaphore_in_delta_cycles(protected_multicast_semaphore);
if global_vvc_busy /= 'L' then
wait until global_vvc_busy = 'L';
end if;
v_was_multicast := true;
end if;
v_start_time := now;
-- semaphore "protected_semaphore" gets released after "wait for 0 ns" in await_cmd_from_sequencer
-- Before the semaphore is released copy shared_vvc_cmd to local variable, so that the shared_vvc_cmd can be used by other VVCs.
v_local_vvc_cmd := shared_vvc_cmd;
-- copy the shared_cmd_idx as it can be changed during this function after the semaphore is released
v_local_cmd_idx := shared_cmd_idx;
-- trigger the target -> vvc continues in await_cmd_from_sequencer
vvc_target.trigger <= '1';
wait for 0 ns;
-- the default value of vvc_target drives trigger to 'L' again
vvc_target <= set_vvc_target_defaults(vvc_target.vvc_name);
while v_ack_cmd_idx /= v_local_cmd_idx loop
wait until global_vvc_ack = '1' for ((v_start_time + timeout) - now);
v_ack_cmd_idx := protected_acknowledge_index.get_index;
if not (global_vvc_ack'event) then
tb_error("Time out for " & C_CMD_INFO & " '" & to_string(v_local_vvc_cmd.proc_call) & "' while waiting for acknowledge from VVC", C_SCOPE);
-- lock the sequencer for 5 delta cycles as it can take so long to get every VVC in normal mode again
wait for 0 ns;
wait for 0 ns;
wait for 0 ns;
wait for 0 ns;
wait for 0 ns;
-- release the semaphore as no VVC can do this
release_semaphore(protected_semaphore);
return;
end if;
end loop;
if (v_was_multicast = true) then
release_semaphore(protected_multicast_semaphore);
end if;
log(ID_UVVM_CMD_ACK, "ACK received. " & format_command_idx(v_local_cmd_idx), C_SCOPE);
-- clean up and prepare for next
wait for 0 ns; -- wait for executor to stop driving global_vvc_ack
end procedure;
procedure acknowledge_cmd (
signal vvc_ack : inout std_logic;
constant command_idx : in natural
) is
begin
-- Drive ack signal for 1 delta cycle only one command index can be acknowledged simultaneously.
while(protected_acknowledge_index.set_index(command_idx) = false) loop
-- if it can't set the acknowledge_index wait for one delta cycle and try again
wait for 0 ns;
end loop;
vvc_ack <= '1';
wait until vvc_ack = '1';
vvc_ack <= 'Z';
wait for 0 ns;
protected_acknowledge_index.release_index;
end procedure;
end package body td_target_support_pkg;
xxxxxxxxxx
--========================================================================================================================
-- Copyright (c) 2017 by Bitvis AS. All rights reserved.
-- You should have received a copy of the license file containing the MIT License (see LICENSE.TXT), if not,
-- contact Bitvis AS <support@bitvis.no>.
--
-- UVVM AND ANY PART THEREOF ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
-- WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
-- OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-- OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH UVVM OR THE USE OR OTHER DEALINGS IN UVVM.
--========================================================================================================================
------------------------------------------------------------------------------------------
-- Description : See library quick reference (under 'doc') and README-file(s)
--
-- Note: This package will be compiled into every single VVC library.
-- As the type t_vvc_target_record is already compiled into every single VVC library,
-- the type definition will be unique for every library, and thus result in a unique
-- procedure signature for every VVC. Hence the shared variable shared_vvc_cmd will
-- refer to only the shared variable defined in the given library.
------------------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library uvvm_util;
context uvvm_util.uvvm_util_context;
library uvvm_vvc_framework;
use uvvm_vvc_framework.ti_vvc_framework_support_pkg.all;
use work.vvc_cmd_pkg.all; -- shared_vvc_response, t_vvc_result
use work.td_target_support_pkg.all;
package td_vvc_framework_common_methods_pkg is
--======================================================================
-- Common Methods
--======================================================================
-------------------------------------------
-- await_completion
-------------------------------------------
-- VVC interpreter IMMEDIATE command
-- - Awaits completion of all commands in the queue for the specified VVC, or
-- until timeout.
procedure await_completion(
signal vvc_target : inout t_vvc_target_record;
constant vvc_instance_idx : in integer;
constant vvc_channel : in t_channel;
constant timeout : in time;
constant msg : in string := ""
);
-------------------------------------------
-- await_completion
-------------------------------------------
-- See description above
procedure await_completion(
signal vvc_target : inout t_vvc_target_record;
constant vvc_instance_idx : in integer;
constant timeout : in time;
constant msg : in string := ""
);
-------------------------------------------
-- await_completion
-------------------------------------------
-- VVC interpreter IMMEDIATE command
-- - Awaits completion of the specified command 'wanted_idx' in the queue for the specified VVC, or
-- until timeout.
procedure await_completion(
signal vvc_target : inout t_vvc_target_record;
constant vvc_instance_idx : in integer;
constant vvc_channel : in t_channel;
constant wanted_idx : in natural;
constant timeout : in time;
constant msg : in string := ""
);
-------------------------------------------
-- await_completion
-------------------------------------------
-- See description above
procedure await_completion(
signal vvc_target : inout t_vvc_target_record;
constant vvc_instance_idx : in integer;
constant wanted_idx : in natural;
constant timeout : in time;
constant msg : in string := ""
);
-------------------------------------------
-- await_any_completion
-------------------------------------------
-- VVC interpreter IMMEDIATE command
-- - Waits for the first of multiple VVCs to finish :
-- - Awaits completion of all commands in the queue for the specified VVC, or
-- - until global_awaiting_completion /= '1' (any of the other involved VVCs completed).
procedure await_any_completion(
signal vvc_target : inout t_vvc_target_record;
constant vvc_instance_idx : in integer;
constant vvc_channel : in t_channel;
constant lastness : in t_lastness;
constant timeout : in time := 100 ns;
constant msg : in string := "";
constant awaiting_completion_idx : in natural := 0
);
-- Overload without vvc_channel
procedure await_any_completion(
signal vvc_target : inout t_vvc_target_record;
constant vvc_instance_idx : in integer;
constant lastness : in t_lastness;
constant timeout : in time := 100 ns;
constant msg : in string := "";
constant awaiting_completion_idx : in natural := 0
);
-- Overload with wanted_idx
-- - Awaits completion of the specified command 'wanted_idx' in the queue for the specified VVC, or
-- - until global_awaiting_completion /= '1' (any of the other involved VVCs completed).
procedure await_any_completion(
signal vvc_target : inout t_vvc_target_record;
constant vvc_instance_idx : in integer;
constant vvc_channel : in t_channel;
constant wanted_idx : in natural;
constant lastness : in t_lastness;
constant timeout : in time := 100 ns;
constant msg : in string := "";
constant awaiting_completion_idx : in natural := 0
);
-- Overload without vvc_channel
procedure await_any_completion(
signal vvc_target : inout t_vvc_target_record;
constant vvc_instance_idx : in integer;
constant wanted_idx : in natural;
constant lastness : in t_lastness;
constant timeout : in time := 100 ns;
constant msg : in string := "";
constant awaiting_completion_idx : in natural := 0
);
-------------------------------------------
-- disable_log_msg
-------------------------------------------
-- VVC interpreter IMMEDIATE command
-- - Disables the specified msg_id for the VVC
procedure disable_log_msg(
signal vvc_target : inout t_vvc_target_record;
constant vvc_instance_idx : in integer;
constant vvc_channel : in t_channel;
constant msg_id : in t_msg_id;
constant msg : in string := "";
constant quietness : t_quietness := NON_QUIET
);
-------------------------------------------
-- disable_log_msg
-------------------------------------------
-- See description above
procedure disable_log_msg(
signal vvc_target : inout t_vvc_target_record;
constant vvc_instance_idx : in integer;
constant msg_id : in t_msg_id;
constant msg : in string := "";
constant quietness : t_quietness := NON_QUIET
);
-------------------------------------------
-- enable_log_msg
-------------------------------------------
-- VVC interpreter IMMEDIATE command
-- - Enables the specified msg_id for the VVC
procedure enable_log_msg(
signal vvc_target : inout t_vvc_target_record;
constant vvc_instance_idx : in integer;
constant vvc_channel : in t_channel;
constant msg_id : in t_msg_id;
constant msg : in string := "";
constant quietness : t_quietness := NON_QUIET
);
-------------------------------------------
-- enable_log_msg
-------------------------------------------
-- See description above
procedure enable_log_msg(
signal vvc_target : inout t_vvc_target_record;
constant vvc_instance_idx : in integer;
constant msg_id : in t_msg_id;
constant msg : in string := "";
constant quietness : t_quietness := NON_QUIET
);
-------------------------------------------
-- flush_command_queue
-------------------------------------------
-- VVC interpreter IMMEDIATE command
-- - Flushes the command queue of the specified VVC
procedure flush_command_queue(
signal vvc_target : inout t_vvc_target_record;
constant vvc_instance_idx : in integer;
constant vvc_channel : in t_channel;
constant msg : in string := ""
);
-------------------------------------------
-- flush_command_queue
-------------------------------------------
-- See description above
procedure flush_command_queue(
signal vvc_target : inout t_vvc_target_record;
constant vvc_instance_idx : in integer;
constant msg : in string := ""
);
-------------------------------------------
-- fetch_result
-------------------------------------------
-- VVC interpreter IMMEDIATE command
-- - Fetches result from a VVC
-- - Requires that result is available (i.e. already executed in respective VVC)
-- - Logs with ID ID_UVVM_CMD_RESULT
-- The 'result' parameter is of type t_vvc_result to
-- support that the BFM returns something other than a std_logic_vector.
procedure fetch_result(
signal vvc_target : inout t_vvc_target_record;
constant vvc_instance_idx : in integer;
constant vvc_channel : in t_channel;
constant wanted_idx : in integer;
variable result : out t_vvc_result;
variable fetch_is_accepted : out boolean;
constant msg : in string := "";
constant alert_level : in t_alert_level := TB_ERROR;
constant caller_name : in string := "base_procedure"
);
-- -- Same as above but without fetch_is_accepted.
-- -- Will trigger alert with alert_level if not OK.
procedure fetch_result(
signal vvc_target : inout t_vvc_target_record;
constant vvc_instance_idx : in integer;
constant vvc_channel : in t_channel;
constant wanted_idx : in integer;
variable result : out t_vvc_result;
constant msg : in string := "";
constant alert_level : in t_alert_level := TB_ERROR
);
-- -- - This version does not use vvc_channel.
-- -- - Fetches result from a VVC
-- -- - Requires that result is available (i.e. already executed in respective VVC)
-- -- - Logs with ID ID_UVVM_CMD_RESULT
procedure fetch_result(
signal vvc_target : inout t_vvc_target_record;
constant vvc_instance_idx : in integer;
constant wanted_idx : in integer;
variable result : out t_vvc_result;
variable fetch_is_accepted : out boolean;
constant msg : in string := "";
constant alert_level : in t_alert_level := TB_ERROR
);
-- -- Same as above but without fetch_is_accepted.
-- -- Will trigger alert with alert_level if not OK.
procedure fetch_result(
signal vvc_target : inout t_vvc_target_record;
constant vvc_instance_idx : in integer;
constant wanted_idx : in integer;
variable result : out t_vvc_result;
constant msg : in string := "";
constant alert_level : in t_alert_level := TB_ERROR
);
-------------------------------------------
-- insert_delay
-------------------------------------------
-- VVC executor QUEUED command
-- - Inserts delay for 'delay' clock cycles
procedure insert_delay(
signal vvc_target : inout t_vvc_target_record;
constant vvc_instance_idx : in integer;
constant vvc_channel : in t_channel;
constant delay : in natural; -- in clock cycles
constant msg : in string := ""
);
-------------------------------------------
-- insert_delay
-------------------------------------------
-- See description above
procedure insert_delay(
signal vvc_target : inout t_vvc_target_record;
constant vvc_instance_idx : in integer;
constant delay : in natural; -- in clock cycles
constant msg : in string := ""
);
-------------------------------------------
-- insert_delay
-------------------------------------------
-- VVC executor QUEUED command
-- - Inserts delay for a given time
procedure insert_delay(
signal vvc_target : inout t_vvc_target_record;
constant vvc_instance_idx : in integer;
constant vvc_channel : in t_channel;
constant delay : in time;
constant msg : in string := ""
);
-------------------------------------------
-- insert_delay
-------------------------------------------
-- See description above
procedure insert_delay(
signal vvc_target : inout t_vvc_target_record;
constant vvc_instance_idx : in integer;
constant delay : in time;
constant msg : in string := ""
);
-------------------------------------------
-- terminate_current_command
-------------------------------------------
-- VVC interpreter IMMEDIATE command
-- - Terminates the current command being processed in the VVC executor
procedure terminate_current_command(
signal vvc_target : inout t_vvc_target_record;
constant vvc_instance_idx : in integer;
constant vvc_channel : in t_channel := NA;
constant msg : in string := ""
);
-------------------------------------------
-- terminate_all_commands
-------------------------------------------
-- VVC interpreter IMMEDIATE command
-- - Terminates the current command being processed in the VVC executor, and
-- flushes the command queue
procedure terminate_all_commands(
signal vvc_target : inout t_vvc_target_record;
constant vvc_instance_idx : in integer;
constant vvc_channel : in t_channel := NA;
constant msg : in string := ""
);
-- Returns the index of the last queued command
impure function get_last_received_cmd_idx(
signal vvc_target : in t_vvc_target_record;
constant vvc_instance_idx : in integer;
constant vvc_channel : in t_channel := NA;
constant msg : in string := ""
) return natural;
end package td_vvc_framework_common_methods_pkg;
package body td_vvc_framework_common_methods_pkg is
--=========================================================================================
-- Methods
--=========================================================================================
-- NOTE: ALL VVCs using this td_vvc_framework_common_methods_pkg package MUST have the following declared in their local vvc_cmd_pkg.
-- - The enumerated t_operation (e.g. AWAIT_COMPLETION, ENABLE_LOG_MSG, etc.)
-- Any VVC based on an older version of td_vvc_framework_common_methods_pkg must - if new operators have been introduced in td_vvc_framework_common_methods_pkg either
-- a) include the new operator(s) in its t_operation, or
-- b) change the use-reference to an older common_methods package.
procedure await_completion(
signal vvc_target : inout t_vvc_target_record;
constant vvc_instance_idx : in integer;
constant vvc_channel : in t_channel;
constant timeout : in time;
constant msg : in string := ""
) is
constant proc_name : string := "await_completion";
constant proc_call : string := proc_name & "(" & to_string(vvc_target, vvc_instance_idx, vvc_channel) -- First part common for all
& ", " & to_string(timeout, ns) & ")";
begin
-- Create command by setting common global 'VVCT' signal record and dedicated VVC 'shared_vvc_cmd' record
-- locking semaphore in set_general_target_and_command_fields to gain exclusive right to VVCT and shared_vvc_cmd
-- semaphore gets unlocked in await_cmd_from_sequencer of the targeted VVC
set_general_target_and_command_fields(vvc_target, vvc_instance_idx, vvc_channel, proc_call, msg, IMMEDIATE, AWAIT_COMPLETION);
shared_vvc_cmd.gen_integer_array(0) := -1; -- All commands must be completed (i.e. not just a selected command index)
shared_vvc_cmd.timeout := timeout;
send_command_to_vvc(vvc_target, timeout);
end procedure;
procedure await_completion(
signal vvc_target : inout t_vvc_target_record;
constant vvc_instance_idx : in integer;
constant timeout : in time;
constant msg : in string := ""
) is
begin
await_completion(vvc_target, vvc_instance_idx, NA, timeout, msg);
end procedure;
procedure await_completion(
signal vvc_target : inout t_vvc_target_record;
constant vvc_instance_idx : in integer;
constant vvc_channel : in t_channel;
constant wanted_idx : in natural;
constant timeout : in time;
constant msg : in string := ""
) is
constant proc_name : string := "await_completion";
constant proc_call : string := proc_name & "(" & to_string(vvc_target, vvc_instance_idx, vvc_channel) -- First part common for all
& ", " & to_string(wanted_idx) & ", " & to_string(timeout, ns) & ")";
begin
-- Create command by setting common global 'VVCT' signal record and dedicated VVC 'shared_vvc_cmd' record
-- locking semaphore in set_general_target_and_command_fields to gain exclusive right to VVCT and shared_vvc_cmd
-- semaphore gets unlocked in await_cmd_from_sequencer of the targeted VVC
set_general_target_and_command_fields(vvc_target, vvc_instance_idx, vvc_channel, proc_call, msg, IMMEDIATE, AWAIT_COMPLETION);
shared_vvc_cmd.gen_integer_array(0) := wanted_idx;
shared_vvc_cmd.timeout := timeout;
send_command_to_vvc(vvc_target, timeout);
end procedure;
procedure await_completion(
signal vvc_target : inout t_vvc_target_record;
constant vvc_instance_idx : in integer;
constant wanted_idx : in natural;
constant timeout : in time;
constant msg : in string := ""
) is
begin
await_completion(vvc_target, vvc_instance_idx, NA, wanted_idx, timeout, msg);
end procedure;
procedure await_any_completion(
signal vvc_target : inout t_vvc_target_record;
constant vvc_instance_idx : in integer;
constant vvc_channel : in t_channel;
constant lastness : in t_lastness;
constant timeout : in time := 100 ns;
constant msg : in string := "";
constant awaiting_completion_idx : in natural := 0 -- Useful when being called by multiple sequencers
) is
constant proc_name : string := "await_any_completion";
constant proc_call : string := proc_name & "(" & to_string(vvc_target, vvc_instance_idx, vvc_channel) -- First part common for all
& ", " & to_string(timeout, ns) & ")";
begin
-- Create command by setting common global 'VVCT' signal record and dedicated VVC 'shared_vvc_cmd' record
-- locking semaphore in set_general_target_and_command_fields to gain exclusive right to VVCT and shared_vvc_cmd
-- semaphore gets unlocked in await_cmd_from_sequencer of the targeted VVC
set_general_target_and_command_fields(vvc_target, vvc_instance_idx, vvc_channel, proc_call, msg, IMMEDIATE, AWAIT_ANY_COMPLETION);
shared_vvc_cmd.gen_integer_array(0) := -1; -- All commands must be completed (i.e. not just a selected command index)
shared_vvc_cmd.gen_integer_array(1) := awaiting_completion_idx;
shared_vvc_cmd.timeout := timeout;
if lastness = LAST then
shared_vvc_cmd.gen_boolean := true; -- LAST
else
shared_vvc_cmd.gen_boolean := false; -- NOT_LAST
end if;
send_command_to_vvc(vvc_target, timeout); -- sets vvc_target.trigger, then waits until global_vvc_ack = '1' for timeout
end procedure;
procedure await_any_completion(
signal vvc_target : inout t_vvc_target_record;
constant vvc_instance_idx : in integer;
constant lastness : in t_lastness;
constant timeout : in time := 100 ns;
constant msg : in string := "";
constant awaiting_completion_idx : in natural := 0
) is
begin
await_any_completion(vvc_target, vvc_instance_idx, NA, lastness, timeout, msg, awaiting_completion_idx);
end procedure;
-- The two below are as the two above, except with wanted_idx as parameter
procedure await_any_completion(
signal vvc_target : inout t_vvc_target_record;
constant vvc_instance_idx : in integer;
constant vvc_channel : in t_channel;
constant wanted_idx : in natural;
constant lastness : in t_lastness;
constant timeout : in time := 100 ns;
constant msg : in string := "";
constant awaiting_completion_idx : in natural := 0 -- Useful when being called by multiple sequencers
) is
constant proc_name : string := "await_any_completion";
constant proc_call : string := proc_name & "(" & to_string(vvc_target, vvc_instance_idx, vvc_channel) -- First part common for all
& ", " & to_string(wanted_idx) & ", " & to_string(timeout, ns) & ")";
begin
-- Create command by setting common global 'VVCT' signal record and dedicated VVC 'shared_vvc_cmd' record
-- locking semaphore in set_general_target_and_command_fields to gain exclusive right to VVCT and shared_vvc_cmd
-- semaphore gets unlocked in await_cmd_from_sequencer of the targeted VVC
set_general_target_and_command_fields(vvc_target, vvc_instance_idx, vvc_channel, proc_call, msg, IMMEDIATE, AWAIT_ANY_COMPLETION);
shared_vvc_cmd.gen_integer_array(0) := wanted_idx;
shared_vvc_cmd.gen_integer_array(1) := awaiting_completion_idx;
shared_vvc_cmd.timeout := timeout;
if lastness = LAST then
-- LAST
shared_vvc_cmd.gen_boolean := true;
else
-- NOT_LAST : Timeout must be handled in interpreter_await_any_completion
-- becuase the command is always acknowledged immediately by the VVC to allow the sequencer to continue
shared_vvc_cmd.gen_boolean := false;
end if;
send_command_to_vvc(vvc_target, timeout);
end procedure;
procedure await_any_completion(
signal vvc_target : inout t_vvc_target_record;
constant vvc_instance_idx : in integer;
constant wanted_idx : in natural;
constant lastness : in t_lastness;
constant timeout : in time := 100 ns;
constant msg : in string := "";
constant awaiting_completion_idx : in natural := 0 -- Useful when being called by multiple sequencers
) is
begin
await_any_completion(vvc_target, vvc_instance_idx, NA, wanted_idx, lastness, timeout, msg, awaiting_completion_idx);
end procedure;
procedure disable_log_msg(
signal vvc_target : inout t_vvc_target_record;
constant vvc_instance_idx : in integer;
constant vvc_channel : in t_channel;
constant msg_id : in t_msg_id;
constant msg : in string := "";
constant quietness : t_quietness := NON_QUIET
) is
constant proc_name : string := "disable_log_msg";
constant proc_call : string := proc_name & "(" & to_string(vvc_target, vvc_instance_idx, vvc_channel) -- First part common for all
& ", " & to_upper(to_string(msg_id)) & ")";
begin
-- Create command by setting common global 'VVCT' signal record and dedicated VVC 'shared_vvc_cmd' record
-- locking semaphore in set_general_target_and_command_fields to gain exclusive right to VVCT and shared_vvc_cmd
-- semaphore gets unlocked in await_cmd_from_sequencer of the targeted VVC
set_general_target_and_command_fields(vvc_target, vvc_instance_idx, vvc_channel, proc_call, msg, IMMEDIATE, DISABLE_LOG_MSG);
shared_vvc_cmd.msg_id := msg_id;
shared_vvc_cmd.quietness := quietness;
send_command_to_vvc(vvc_target);
end procedure;
procedure disable_log_msg(
signal vvc_target : inout t_vvc_target_record;
constant vvc_instance_idx : in integer;
constant msg_id : in t_msg_id;
constant msg : in string := "";
constant quietness : t_quietness := NON_QUIET
) is
begin
disable_log_msg(vvc_target, vvc_instance_idx, NA, msg_id, msg, quietness);
end procedure;
procedure enable_log_msg(
signal vvc_target : inout t_vvc_target_record;
constant vvc_instance_idx : in integer;
constant vvc_channel : in t_channel;
constant msg_id : in t_msg_id;
constant msg : in string := "";
constant quietness : t_quietness := NON_QUIET
) is
constant proc_name : string := "enable_log_msg";
constant proc_call : string := proc_name & "(" & to_string(vvc_target, vvc_instance_idx, vvc_channel) -- First part common for all
& ", " & to_upper(to_string(msg_id)) & ")";
begin
-- Create command by setting common global 'VVCT' signal record and dedicated VVC 'shared_vvc_cmd' record
-- locking semaphore in set_general_target_and_command_fields to gain exclusive right to VVCT and shared_vvc_cmd
-- semaphore gets unlocked in await_cmd_from_sequencer of the targeted VVC
set_general_target_and_command_fields(vvc_target, vvc_instance_idx, vvc_channel, proc_call, msg, IMMEDIATE, ENABLE_LOG_MSG);
shared_vvc_cmd.msg_id := msg_id;
shared_vvc_cmd.quietness := quietness;
send_command_to_vvc(vvc_target);
end procedure;
procedure enable_log_msg(
signal vvc_target : inout t_vvc_target_record;
constant vvc_instance_idx : in integer;
constant msg_id : in t_msg_id;
constant msg : in string := "";
constant quietness : t_quietness := NON_QUIET
) is
begin
enable_log_msg(vvc_target, vvc_instance_idx, NA, msg_id, msg, quietness);
end procedure;
procedure flush_command_queue(
signal vvc_target : inout t_vvc_target_record;
constant vvc_instance_idx : in integer;
constant vvc_channel : in t_channel;
constant msg : in string := ""
) is
constant proc_name : string := "flush_command_queue";
constant proc_call : string := proc_name & "(" & to_string(vvc_target, vvc_instance_idx, vvc_channel) & ")";
begin
-- Create command by setting common global 'VVCT' signal record and dedicated VVC 'shared_vvc_cmd' record
-- locking semaphore in set_general_target_and_command_fields to gain exclusive right to VVCT and shared_vvc_cmd
-- semaphore gets unlocked in await_cmd_from_sequencer of the targeted VVC
set_general_target_and_command_fields(vvc_target, vvc_instance_idx, vvc_channel, proc_call, msg, IMMEDIATE, FLUSH_COMMAND_QUEUE);
send_command_to_vvc(vvc_target);
end procedure;
procedure flush_command_queue(
signal vvc_target : inout t_vvc_target_record;
constant vvc_instance_idx : in integer;
constant msg : in string := ""
) is
begin
flush_command_queue(vvc_target, vvc_instance_idx, NA, msg);
end procedure;
-- Requires that result is available (i.e. already executed in respective VVC)
-- The four next procedures are overloads for when 'result' is of type work.vvc_cmd_pkg.t_vvc_result
procedure fetch_result(
signal vvc_target : inout t_vvc_target_record;
constant vvc_instance_idx : in integer;
constant vvc_channel : in t_channel;
constant wanted_idx : in integer;
variable result : out t_vvc_result;
variable fetch_is_accepted : out boolean;
constant msg : in string := "";
constant alert_level : in t_alert_level := TB_ERROR;
constant caller_name : in string := "base_procedure"
) is
constant proc_name : string := "fetch_result";
constant proc_call : string := proc_name & "(" & to_string(vvc_target, vvc_instance_idx, vvc_channel) -- First part common for all
& ", " & to_string(wanted_idx) & ")";
begin
await_semaphore_in_delta_cycles(protected_response_semaphore);
-- Create command by setting common global 'VVCT' signal record and dedicated VVC 'shared_vvc_cmd' record
-- locking semaphore in set_general_target_and_command_fields to gain exclusive right to VVCT and shared_vvc_cmd
-- semaphore gets unlocked in await_cmd_from_sequencer of the targeted VVC
set_general_target_and_command_fields(vvc_target, vvc_instance_idx, vvc_channel, proc_call, msg, IMMEDIATE, FETCH_RESULT);
shared_vvc_cmd.gen_integer_array(0) := wanted_idx;
send_command_to_vvc(vvc_target);
-- Post process
result := shared_vvc_response.result;
fetch_is_accepted := shared_vvc_response.fetch_is_accepted;
if caller_name = "base_procedure" then
log(ID_UVVM_CMD_RESULT, proc_call & ": Legal=>" & to_string(shared_vvc_response.fetch_is_accepted) & ", Result=>" & to_string(result) & format_command_idx(shared_cmd_idx), C_SCOPE); -- Get and ack the new command
end if;
release_semaphore(protected_response_semaphore);
end procedure;
procedure fetch_result(
signal vvc_target : inout t_vvc_target_record;
constant vvc_instance_idx : in integer;
constant vvc_channel : in t_channel;
constant wanted_idx : in integer;
variable result : out t_vvc_result;
constant msg : in string := "";
constant alert_level : in t_alert_level := TB_ERROR
) is
variable v_fetch_is_accepted : boolean;
constant proc_name : string := "fetch_result";
constant proc_call : string := proc_name & "(" & to_string(vvc_target, vvc_instance_idx, vvc_channel) -- First part common for all
& ", " & to_string(wanted_idx) & ")";
begin
fetch_result(vvc_target, vvc_instance_idx, vvc_channel, wanted_idx, result, v_fetch_is_accepted, msg, alert_level, proc_name & "_with_check_of_ok");
if v_fetch_is_accepted then
log(ID_UVVM_CMD_RESULT, proc_call & ": Legal=>" & to_string(v_fetch_is_accepted) & ", Result=>" & format_command_idx(shared_cmd_idx), C_SCOPE); -- Get and ack the new command
else
alert(alert_level, "fetch_result(" & to_string(wanted_idx) & "): " & add_msg_delimiter(msg) & "." &
" Failed. Trying to fetch result from not yet executed command or from command with no result stored. " & format_command_idx(shared_cmd_idx), C_SCOPE);
end if;
end procedure;
procedure fetch_result(
signal vvc_target : inout t_vvc_target_record;
constant vvc_instance_idx : in integer;
constant wanted_idx : in integer;
variable result : out t_vvc_result;
variable fetch_is_accepted : out boolean;
constant msg : in string := "";
constant alert_level : in t_alert_level := TB_ERROR
) is
begin
fetch_result(vvc_target, vvc_instance_idx, NA, wanted_idx, result, fetch_is_accepted, msg, alert_level);
end procedure;
procedure fetch_result(
signal vvc_target : inout t_vvc_target_record;
constant vvc_instance_idx : in integer;
constant wanted_idx : in integer;
variable result : out t_vvc_result;
constant msg : in string := "";
constant alert_level : in t_alert_level := TB_ERROR
) is
begin
fetch_result(vvc_target, vvc_instance_idx, NA, wanted_idx, result, msg, alert_level);
end procedure;
procedure insert_delay(
signal vvc_target : inout t_vvc_target_record;
constant vvc_instance_idx : in integer;
constant vvc_channel : in t_channel;
constant delay : in natural; -- in clock cycles
constant msg : in string := ""
) is
constant proc_name : string := "insert_delay";
constant proc_call : string := proc_name & "(" & to_string(vvc_target, vvc_instance_idx, vvc_channel) -- First part common for all
& ", " & to_string(delay) & ")";
begin
-- Create command by setting common global 'VVCT' signal record and dedicated VVC 'shared_vvc_cmd' record
-- locking semaphore in set_general_target_and_command_fields to gain exclusive right to VVCT and shared_vvc_cmd
-- semaphore gets unlocked in await_cmd_from_sequencer of the targeted VVC
set_general_target_and_command_fields(vvc_target, vvc_instance_idx, vvc_channel, proc_call, msg, QUEUED, INSERT_DELAY);
shared_vvc_cmd.gen_integer_array(0) := delay;
send_command_to_vvc(vvc_target);
end procedure;
procedure insert_delay(
signal vvc_target : inout t_vvc_target_record;
constant vvc_instance_idx : in integer;
constant delay : in natural; -- in clock cycles
constant msg : in string := ""
) is
begin
insert_delay(vvc_target, vvc_instance_idx, NA, delay, msg);
end procedure;
procedure insert_delay(
signal vvc_target : inout t_vvc_target_record;
constant vvc_instance_idx : in integer;
constant vvc_channel : in t_channel;
constant delay : in time;
constant msg : in string := ""
) is
constant proc_name : string := "insert_delay";
constant proc_call : string := proc_name & "(" & to_string(vvc_target, vvc_instance_idx, vvc_channel) -- First part common for all
& ", " & to_string(delay) & ")";
begin
-- Create command by setting common global 'VVCT' signal record and dedicated VVC 'shared_vvc_cmd' record
-- locking semaphore in set_general_target_and_command_fields to gain exclusive right to VVCT and shared_vvc_cmd
-- semaphore gets unlocked in await_cmd_from_sequencer of the targeted VVC
set_general_target_and_command_fields(vvc_target, vvc_instance_idx, vvc_channel, proc_call, msg, QUEUED, INSERT_DELAY);
shared_vvc_cmd.delay := delay;
send_command_to_vvc(vvc_target);
end procedure;
procedure insert_delay(
signal vvc_target : inout t_vvc_target_record;
constant vvc_instance_idx : in integer;
constant delay : in time;
constant msg : in string := ""
) is
begin
insert_delay(vvc_target, vvc_instance_idx, NA, delay, msg);
end procedure;
procedure terminate_current_command(
signal vvc_target : inout t_vvc_target_record;
constant vvc_instance_idx : in integer;
constant vvc_channel : in t_channel := NA;
constant msg : in string := ""
) is
constant proc_name : string := "terminate_current_command";
constant proc_call : string := proc_name & "(" & to_string(vvc_target, vvc_instance_idx, vvc_channel) -- First part common for all
& ")";
begin
-- Create command by setting common global 'VVCT' signal record and dedicated VVC 'shared_vvc_cmd' record
-- locking semaphore in set_general_target_and_command_fields to gain exclusive right to VVCT and shared_vvc_cmd
-- semaphore gets unlocked in await_cmd_from_sequencer of the targeted VVC
set_general_target_and_command_fields(vvc_target, vvc_instance_idx, vvc_channel, proc_call, msg, IMMEDIATE, TERMINATE_CURRENT_COMMAND);
send_command_to_vvc(vvc_target);
end procedure;
procedure terminate_all_commands(
signal vvc_target : inout t_vvc_target_record;
constant vvc_instance_idx : in integer;
constant vvc_channel : in t_channel := NA;
constant msg : in string := ""
) is
begin
flush_command_queue(vvc_target, vvc_instance_idx, vvc_channel,msg);
terminate_current_command(vvc_target, vvc_instance_idx, vvc_channel, msg);
end procedure;
-- Returns the index of the last queued command
impure function get_last_received_cmd_idx(
signal vvc_target : in t_vvc_target_record;
constant vvc_instance_idx : in integer;
constant vvc_channel : in t_channel := NA;
constant msg : in string := ""
) return natural is
variable v_cmd_idx : integer := -1;
begin
v_cmd_idx := shared_vvc_last_received_cmd_idx(vvc_channel, vvc_instance_idx);
check_value(v_cmd_idx /= -1, tb_error, "Channel " & to_string(vvc_channel) & " not supported on VVC " & vvc_target.vvc_name, C_SCOPE, ID_NEVER);
if v_cmd_idx /= -1 then
return v_cmd_idx;
else
-- return 0 in case of failure
return 0;
end if;
end function;
end package body td_vvc_framework_common_methods_pkg;
xxxxxxxxxx
--========================================================================================================================
-- This VVC was generated with Bitvis VVC Generator
--========================================================================================================================
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library uvvm_util;
context uvvm_util.uvvm_util_context;
library uvvm_vvc_framework;
use uvvm_vvc_framework.ti_vvc_framework_support_pkg.all;
use work.counter_bfm_pkg.all;
use work.vvc_cmd_pkg.all;
use work.td_target_support_pkg.all;
--========================================================================================================================
--========================================================================================================================
package vvc_methods_pkg is
--========================================================================================================================
-- Types and constants for the COUNTER VVC
--========================================================================================================================
constant C_VVC_NAME : string := "COUNTER_VVC";
signal COUNTER_VVCT : t_vvc_target_record := set_vvc_target_defaults(C_VVC_NAME);
alias THIS_VVCT : t_vvc_target_record is COUNTER_VVCT;
alias t_bfm_config is t_counter_bfm_config;
-- Type found in UVVM-Util types_pkg
constant C_COUNTER_INTER_BFM_DELAY_DEFAULT : t_inter_bfm_delay := (
delay_type => NO_DELAY,
delay_in_time => 0 ns,
inter_bfm_delay_violation_severity => WARNING
);
type t_vvc_config is
record
inter_bfm_delay : t_inter_bfm_delay;-- Minimum delay between BFM accesses from the VVC. If parameter delay_type is set to NO_DELAY, BFM accesses will be back to back, i.e. no delay.
cmd_queue_count_max : natural; -- Maximum pending number in command queue before queue is full. Adding additional commands will result in an ERROR.
cmd_queue_count_threshold : natural; -- An alert with severity 'cmd_queue_count_threshold_severity' will be issued if command queue exceeds this count. Used for early warning if command queue is almost full. Will be ignored if set to 0.
cmd_queue_count_threshold_severity : t_alert_level; -- Severity of alert to be initiated if exceeding cmd_queue_count_threshold
result_queue_count_max : natural;
result_queue_count_threshold_severity : t_alert_level;
result_queue_count_threshold : natural;
bfm_config : t_counter_bfm_config; -- Configuration for the BFM. See BFM quick reference
msg_id_panel : t_msg_id_panel; -- VVC dedicated message ID panel
end record;
type t_vvc_config_array is array (natural range <>) of t_vvc_config;
constant C_COUNTER_VVC_CONFIG_DEFAULT : t_vvc_config := (
inter_bfm_delay => C_COUNTER_INTER_BFM_DELAY_DEFAULT,
cmd_queue_count_max => C_CMD_QUEUE_COUNT_MAX, -- from adaptation package
cmd_queue_count_threshold => C_CMD_QUEUE_COUNT_THRESHOLD,
cmd_queue_count_threshold_severity => C_CMD_QUEUE_COUNT_THRESHOLD_SEVERITY,
result_queue_count_max => C_RESULT_QUEUE_COUNT_MAX,
result_queue_count_threshold_severity => C_RESULT_QUEUE_COUNT_THRESHOLD_SEVERITY,
result_queue_count_threshold => C_RESULT_QUEUE_COUNT_THRESHOLD,
bfm_config => C_COUNTER_BFM_CONFIG_DEFAULT,
msg_id_panel => C_VVC_MSG_ID_PANEL_DEFAULT
);
type t_vvc_status is
record
current_cmd_idx : natural;
previous_cmd_idx : natural;
pending_cmd_cnt : natural;
end record;
type t_vvc_status_array is array (natural range <>) of t_vvc_status;
constant C_VVC_STATUS_DEFAULT : t_vvc_status := (
current_cmd_idx => 0,
previous_cmd_idx => 0,
pending_cmd_cnt => 0
);
-- Transaction information to include in the wave view during simulation
type t_transaction_info is
record
operation : t_operation;
msg : string(1 to C_VVC_CMD_STRING_MAX_LENGTH);
--<USER_INPUT> Fields that could be useful to track in the waveview can be placed in this record.
data : std_logic_vector(C_VVC_CMD_DATA_MAX_LENGTH-1 downto 0);
Q : std_logic_vector(C_VVC_CMD_DATA_MAX_LENGTH-1 downto 0);
cycles : natural;
end record;
type t_transaction_info_array is array (natural range <>) of t_transaction_info;
constant C_TRANSACTION_INFO_DEFAULT : t_transaction_info := (
--<USER_INPUT> Set the data fields added to the t_transaction_info record to
-- their default values here.
-- Example:
data => (others => '0'),
Q => (others => '0'),
cycles => 0,
operation => NO_OPERATION,
msg => (others => ' ')
);
shared variable shared_counter_vvc_config : t_vvc_config_array(0 to C_MAX_VVC_INSTANCE_NUM-1) := (others => C_COUNTER_VVC_CONFIG_DEFAULT);
shared variable shared_counter_vvc_status : t_vvc_status_array(0 to C_MAX_VVC_INSTANCE_NUM-1) := (others => C_VVC_STATUS_DEFAULT);
shared variable shared_counter_transaction_info : t_transaction_info_array(0 to C_MAX_VVC_INSTANCE_NUM-1) := (others => C_TRANSACTION_INFO_DEFAULT);
--========================================================================================================================
-- Methods dedicated to this VVC
-- - These procedures are called from the testbench in order to queue BFM calls
-- in the VVC command queue. The VVC will store and forward these calls to the
-- COUNTER BFM when the command is at the from of the VVC command queue.
--========================================================================================================================
--<USER_INPUT> Please insert the VVC procedure declarations here
procedure counter_reset(
signal VVCT : inout t_vvc_target_record;
constant vvc_instance_idx : in integer;
constant msg : in string
);
procedure counter_check(
signal VVCT : inout t_vvc_target_record;
constant vvc_instance_idx : in integer;
constant Q_exp : in std_logic_vector;
constant msg : in string
);
procedure counter_load(
signal VVCT : inout t_vvc_target_record;
constant vvc_instance_idx : in integer;
constant data_value : in std_logic_vector;
constant msg : in string
);
procedure counter_count_up(
signal VVCT : inout t_vvc_target_record;
constant vvc_instance_idx : in integer;
constant cycles : in natural;
constant msg : in string
);
-- IYHT: check counting down
procedure counter_hold(
signal VVCT : inout t_vvc_target_record;
constant vvc_instance_idx : in integer;
constant cycles : in natural;
constant msg : in string
);
end package vvc_methods_pkg;
package body vvc_methods_pkg is
--========================================================================================================================
-- Methods dedicated to this VVC
--========================================================================================================================
--<USER_INPUT> Please insert the VVC procedure implementations here.
-- These procedures will be used to forward commands to the VVC executor, which will
-- call the corresponding BFM procedures.
procedure counter_reset(
signal VVCT : inout t_vvc_target_record;
constant vvc_instance_idx : in integer;
constant msg : in string
) is
constant proc_name : string := "counter_reset";
constant proc_call : string := proc_name & "()";
begin
-- Create command by setting common global 'VVCT' signal record and dedicated VVC 'shared_vvc_cmd' record
-- locking semaphore in set_general_target_and_command_fields to gain exclusive right to VVCT and shared_vvc_cmd
-- semaphore gets unlocked in await_cmd_from_sequencer of the targeted VVC
set_general_target_and_command_fields(VVCT, vvc_instance_idx, proc_call, msg, QUEUED, RESET);
send_command_to_vvc(VVCT);
end procedure;
procedure counter_check(
signal VVCT : inout t_vvc_target_record;
constant vvc_instance_idx : in integer;
constant Q_exp : in std_logic_vector;
constant msg : in string
) is
constant proc_name : string := "counter_check";
constant proc_call : string := proc_name & "(" & to_string(VVCT, vvc_instance_idx) -- First part common for all
& ", " & to_string(Q_exp, HEX, AS_IS, INCL_RADIX) & ")";
constant v_normalised_Q : std_logic_vector(C_VVC_CMD_DATA_MAX_LENGTH-1 downto 0) :=
normalize_and_check(Q_exp, shared_vvc_cmd.Q, ALLOW_EXACT_ONLY, "Q_exp", "shared_vvc_cmd.Q", proc_call & " called with too wide Q_exp. " & msg);
begin
-- Create command by setting common global 'VVCT' signal record and dedicated VVC 'shared_vvc_cmd' record
-- locking semaphore in set_general_target_and_command_fields to gain exclusive right to VVCT and shared_vvc_cmd
-- semaphore gets unlocked in await_cmd_from_sequencer of the targeted VVC
set_general_target_and_command_fields(VVCT, vvc_instance_idx, proc_call, msg, QUEUED, CHECK);
shared_vvc_cmd.Q := v_normalised_Q;
send_command_to_vvc(VVCT);
end procedure;
procedure counter_load(
signal VVCT : inout t_vvc_target_record;
constant vvc_instance_idx : in integer;
constant data_value : in std_logic_vector;
constant msg : in string
) is
constant proc_name : string := "counter_load";
constant proc_call : string := proc_name & "(" & to_string(VVCT, vvc_instance_idx) -- First part common for all
& ", " & to_string(data_value, HEX, AS_IS, INCL_RADIX) & ")";
constant v_normalised_data : std_logic_vector(C_VVC_CMD_DATA_MAX_LENGTH-1 downto 0) :=
normalize_and_check(data_value, shared_vvc_cmd.data, ALLOW_WIDER_NARROWER, "data_value", "shared_vvc_cmd.data", proc_call & " called with too wide data_value. " & msg);
begin
-- Create command by setting common global 'VVCT' signal record and dedicated VVC 'shared_vvc_cmd' record
-- locking semaphore in set_general_target_and_command_fields to gain exclusive right to VVCT and shared_vvc_cmd
-- semaphore gets unlocked in await_cmd_from_sequencer of the targeted VVC
set_general_target_and_command_fields(VVCT, vvc_instance_idx, proc_call, msg, QUEUED, LOAD);
shared_vvc_cmd.data := v_normalised_data;
send_command_to_vvc(VVCT);
end procedure;
procedure counter_count_up(
signal VVCT : inout t_vvc_target_record;
constant vvc_instance_idx : in integer;
constant cycles : in natural;
constant msg : in string
) is
use std.textio.side;
constant proc_name : string := "counter_count_up";
constant proc_call : string := proc_name & "(" & to_string(VVCT, vvc_instance_idx) -- First part common for all
& ", " & integer'image(cycles) & ")";
begin
-- Create command by setting common global 'VVCT' signal record and dedicated VVC 'shared_vvc_cmd' record
-- locking semaphore in set_general_target_and_command_fields to gain exclusive right to VVCT and shared_vvc_cmd
-- semaphore gets unlocked in await_cmd_from_sequencer of the targeted VVC
set_general_target_and_command_fields(VVCT, vvc_instance_idx, proc_call, msg, QUEUED, COUNT_UP);
shared_vvc_cmd.cycles := cycles;
send_command_to_vvc(VVCT);
end procedure;
-- IYHT: check counting down
procedure counter_hold(
signal VVCT : inout t_vvc_target_record;
constant vvc_instance_idx : in integer;
constant cycles : in natural;
constant msg : in string
) is
use std.textio.side;
constant proc_name : string := "counter_hold";
constant proc_call : string := proc_name & "(" & to_string(VVCT, vvc_instance_idx) -- First part common for all
& ", " & integer'image(cycles) & ")";
begin
-- Create command by setting common global 'VVCT' signal record and dedicated VVC 'shared_vvc_cmd' record
-- locking semaphore in set_general_target_and_command_fields to gain exclusive right to VVCT and shared_vvc_cmd
-- semaphore gets unlocked in await_cmd_from_sequencer of the targeted VVC
set_general_target_and_command_fields(VVCT, vvc_instance_idx, proc_call, msg, QUEUED, HOLD);
shared_vvc_cmd.cycles := cycles;
send_command_to_vvc(VVCT);
end procedure;
end package body vvc_methods_pkg;
xxxxxxxxxx
--========================================================================================================================
-- Copyright (c) 2017 by Bitvis AS. All rights reserved.
-- You should have received a copy of the license file containing the MIT License (see LICENSE.TXT), if not,
-- contact Bitvis AS <support@bitvis.no>.
--
-- UVVM AND ANY PART THEREOF ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
-- WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
-- OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-- OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH UVVM OR THE USE OR OTHER DEALINGS IN UVVM.
--========================================================================================================================
------------------------------------------------------------------------------------------
-- Description : See library quick reference (under 'doc') and README-file(s)
------------------------------------------------------------------------------------------
--===============================================================================================
-- td_cmd_queue_pkg
-- - Target dependent command queue package
--===============================================================================================
library uvvm_vvc_framework;
use uvvm_vvc_framework.ti_generic_queue_pkg;
use work.vvc_cmd_pkg.all;
package td_cmd_queue_pkg is new uvvm_vvc_framework.ti_generic_queue_pkg
generic map (t_generic_element => t_vvc_cmd_record);
--===============================================================================================
-- td_result_queue_pkg
-- - Target dependent result queue package
--===============================================================================================
library uvvm_vvc_framework;
use uvvm_vvc_framework.ti_generic_queue_pkg;
use work.vvc_cmd_pkg.all;
package td_result_queue_pkg is new uvvm_vvc_framework.ti_generic_queue_pkg
generic map (t_generic_element => t_vvc_result_queue_element);
--========================================================================================================================
-- Copyright (c) 2017 by Bitvis AS. All rights reserved.
-- You should have received a copy of the license file containing the MIT License (see LICENSE.TXT), if not,
-- contact Bitvis AS <support@bitvis.no>.
--
-- UVVM AND ANY PART THEREOF ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
-- WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
-- OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-- OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH UVVM OR THE USE OR OTHER DEALINGS IN UVVM.
--========================================================================================================================
------------------------------------------------------------------------------------------
-- Description : See library quick reference (under 'doc') and README-file(s)
------------------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library uvvm_util;
context uvvm_util.uvvm_util_context;
library uvvm_vvc_framework;
use uvvm_vvc_framework.ti_vvc_framework_support_pkg.all;
use work.td_cmd_queue_pkg.all;
use work.td_result_queue_pkg.all;
use work.vvc_cmd_pkg.all;
use work.vvc_methods_pkg.all;
use work.td_vvc_framework_common_methods_pkg.all;
use work.td_target_support_pkg.all;
--=================================================================================================
--=================================================================================================
--=================================================================================================
package td_vvc_entity_support_pkg is
type t_vvc_labels is record
scope : string(1 to C_LOG_SCOPE_WIDTH);
vvc_name : string(1 to C_LOG_SCOPE_WIDTH-2);
instance_idx : natural;
channel : t_channel;
end record;
-------------------------------------------
-- assign_vvc_labels
-------------------------------------------
-- This function puts common VVC labels into a record - to reduce the number of procedure parameters
function assign_vvc_labels(
scope : string;
vvc_name : string;
instance_idx : integer;
channel : t_channel
) return t_vvc_labels;
-------------------------------------------
-- format_msg
-------------------------------------------
-- Generates a sting containing the command message and index
-- - Format: Message [index]
impure function format_msg(
command : t_vvc_cmd_record
) return string;
-------------------------------------------
-- vvc_constructor
-------------------------------------------
-- Procedure used as concurrent process in the VVCs
-- - Sets up the vvc_config, command queue and result_queue
-- - Verifies that UVVM has been initialized
procedure vvc_constructor(
constant scope : in string;
constant instance_idx : in natural;
variable vvc_config : inout t_vvc_config;
variable command_queue : inout work.td_cmd_queue_pkg.t_generic_queue;
variable result_queue : inout work.td_result_queue_pkg.t_generic_queue;
constant bfm_config : in t_bfm_config;
constant cmd_queue_count_max : in natural;
constant cmd_queue_count_threshold : in natural;
constant cmd_queue_count_threshold_severity : in t_alert_level;
constant result_queue_count_max : in natural;
constant result_queue_count_threshold : in natural;
constant result_queue_count_threshold_severity : in t_alert_level
);
-------------------------------------------
-- initialize_interpreter
-------------------------------------------
-- Initialises the VVC interpreter
-- - Clears terminate_current_cmd.set to '0'
procedure initialize_interpreter (
signal terminate_current_cmd : out t_flag_record;
signal global_awaiting_completion : out std_logic_vector(C_MAX_NUM_SEQUENCERS-1 downto 0)
);
-------------------------------------------
-- await_cmd_from_sequencer
-------------------------------------------
-- Waits for a command from the central sequencer. Continues on matching VVC, Instance, Name and Channel (unless channel = NA)
-- - Log at start using ID_CMD_INTERPRETER_WAIT and at the end using ID_CMD_INTERPRETER
procedure await_cmd_from_sequencer(
constant vvc_labels : in t_vvc_labels;
constant vvc_config : in t_vvc_config;
signal VVCT : in t_vvc_target_record;
signal VVC_BROADCAST : inout std_logic;
signal global_vvc_busy : inout std_logic;
signal vvc_ack : out std_logic;
constant shared_vvc_cmd : in t_vvc_cmd_record;
variable output_vvc_cmd : out t_vvc_cmd_record
);
-------------------------------------------
-- put_command_on_queue
-------------------------------------------
-- Puts the received command (by Interpreter) on the VVC queue (for later retrieval by Executor)
procedure put_command_on_queue(
constant command : in t_vvc_cmd_record;
variable command_queue : inout work.td_cmd_queue_pkg.t_generic_queue;
variable vvc_status : inout t_vvc_status;
signal queue_is_increasing : out boolean
);
-------------------------------------------
-- interpreter_await_completion
-------------------------------------------
-- Immediate command: await_completion (in interpreter)
-- - Command description in Quick reference for UVVM common methods
-- - Will wait until given command(s) is completed by the excutor (if not already completed)
-- - Log using ID_IMMEDIATE_CMD when await completed
-- - Log using ID_IMMEDIATE_CMD_WAIT if waiting is actually needed
procedure interpreter_await_completion(
constant command : in t_vvc_cmd_record;
variable command_queue : inout work.td_cmd_queue_pkg.t_generic_queue;
constant vvc_config : in t_vvc_config;
signal executor_is_busy : in boolean;
constant vvc_labels : in t_vvc_labels;
signal last_cmd_idx_executed : in natural;
constant await_completion_pending_msg_id : in t_msg_id := ID_IMMEDIATE_CMD_WAIT;
constant await_completion_finished_msg_id : in t_msg_id := ID_IMMEDIATE_CMD
);
-------------------------------------------
-- interpreter_await_any_completion
-------------------------------------------
-- Immediate command: await_any_completion() (in interpreter)
-- - This procedure is called by the interpreter if sequencer calls await_any_completion()
-- - It waits for the first of the following :
-- 'await_completion' of this VVC, or
-- until global_awaiting_completion(idx) /= '1' (any of the other involved VVCs completed).
-- - Refer to description in Quick reference for UVVM common methods
-- - Log using ID_IMMEDIATE_CMD when the wait completed
-- - Log using ID_IMMEDIATE_CMD_WAIT if waiting is actually needed
procedure interpreter_await_any_completion(
constant command : in t_vvc_cmd_record;
variable command_queue : inout work.td_cmd_queue_pkg.t_generic_queue;
constant vvc_config : in t_vvc_config;
signal executor_is_busy : in boolean;
constant vvc_labels : in t_vvc_labels;
signal last_cmd_idx_executed : in natural;
signal global_awaiting_completion : inout std_logic_vector; -- Handshake with other VVCs performing await_any_completion
constant await_completion_pending_msg_id : in t_msg_id := ID_IMMEDIATE_CMD_WAIT;
constant await_completion_finished_msg_id : in t_msg_id := ID_IMMEDIATE_CMD
);
-------------------------------------------
-- interpreter_flush_command_queue
-------------------------------------------
-- Immediate command: flush_command_queue (in interpreter)
-- - Command description in Quick reference for UVVM common methods
-- - Log using ID_IMMEDIATE_CMD
procedure interpreter_flush_command_queue(
constant command : in t_vvc_cmd_record;
variable command_queue : inout work.td_cmd_queue_pkg.t_generic_queue;
constant vvc_config : in t_vvc_config;
variable vvc_status : inout t_vvc_status;
constant vvc_labels : in t_vvc_labels
);
-------------------------------------------
-- interpreter_terminate_current_command
-------------------------------------------
-- Immediate command: terminate_current_command (in interpreter)
-- - Command description in Quick reference for UVVM common methods
-- - Log using ID_IMMEDIATE_CMD
procedure interpreter_terminate_current_command(
constant command : in t_vvc_cmd_record;
constant vvc_config : in t_vvc_config;
constant vvc_labels : in t_vvc_labels;
signal terminate_current_cmd : inout t_flag_record
);
-------------------------------------------
-- interpreter_fetch_result
-------------------------------------------
-- Immediate command: interpreter_fetch_result (in interpreter)
-- - Command description in Quick reference for UVVM common methods
-- - Log using ID_IMMEDIATE_CMD
-- t_vvc_response is specific to each VVC,
-- so the BFM can return any type which is then transported from the VVC to the sequencer via a fetch_result() call
procedure interpreter_fetch_result(
variable result_queue : inout work.td_result_queue_pkg.t_generic_queue;
constant command : in t_vvc_cmd_record;
constant vvc_config : in t_vvc_config;
constant vvc_labels : in t_vvc_labels;
constant last_cmd_idx_executed : in natural;
variable shared_vvc_response : inout work.vvc_cmd_pkg.t_vvc_response
);
-------------------------------------------
-- initialize_executor
-------------------------------------------
-- Initialises the VVC executor
-- - Resets terminate_current_cmd.reset flag
procedure initialize_executor (
signal terminate_current_cmd : inout t_flag_record
);
-------------------------------------------
-- fetch_command_and_prepare_executor
-------------------------------------------
-- Fetches a command from the queue (waits until available if needed)
-- - Log command using ID_CMD_EXECUTOR
-- - Log using ID_CMD_EXECUTOR_WAIT if queue is empty
-- - Sets relevant flags
procedure fetch_command_and_prepare_executor(
variable command : inout t_vvc_cmd_record;
variable command_queue : inout work.td_cmd_queue_pkg.t_generic_queue;
constant vvc_config : in t_vvc_config;
variable vvc_status : inout t_vvc_status;
signal queue_is_increasing : in boolean;
signal executor_is_busy : inout boolean;
constant vvc_labels : in t_vvc_labels
);
-------------------------------------------
-- store_result
-------------------------------------------
-- Store result from BFM in the VVC's result_queue
-- The result_queue is used to store a generic type that is returned from
-- a read/expect BFM procedure.
-- It can be fetched later using fetch_result() to return it from the VVC to sequencer
procedure store_result(
variable result_queue : inout work.td_result_queue_pkg.t_generic_queue;
constant cmd_idx : in natural;
constant result : in t_vvc_result
);
-------------------------------------------
-- insert_inter_bfm_delay_if_requested
-------------------------------------------
-- Inserts delay of either START2START or FINISH2START in time, given that
-- - vvc_config inter-bfm delay type is not set to NO_DELAY
-- - command_is_bfm_access is set to true
-- - Both timestamps are not set to 0 ns.
-- A log message with ID ID_CMD_EXECUTOR is issued when the delay begins and
-- when it has finished delaying.
procedure insert_inter_bfm_delay_if_requested(
constant vvc_config : in t_vvc_config;
constant command_is_bfm_access : in boolean;
constant timestamp_start_of_last_bfm_access : in time;
constant timestamp_end_of_last_bfm_access : in time;
constant scope : in string := C_SCOPE
);
function broadcast_cmd_to_shared_cmd (
constant broadcast_cmd : t_broadcastable_cmd
) return t_operation;
function get_command_type_from_operation (
constant broadcast_cmd : t_broadcastable_cmd
) return t_immediate_or_queued;
procedure populate_shared_vvc_cmd_with_broadcast (
variable output_vvc_cmd : out t_vvc_cmd_record
);
end package td_vvc_entity_support_pkg;
package body td_vvc_entity_support_pkg is
function assign_vvc_labels(
scope : string;
vvc_name : string;
instance_idx : integer;
channel : t_channel
) return t_vvc_labels is
variable vvc_labels : t_vvc_labels;
begin
vvc_labels.scope := pad_string(scope, NUL, vvc_labels.scope'length);
vvc_labels.vvc_name := pad_string(vvc_name, NUL, vvc_labels.vvc_name'length);
vvc_labels.instance_idx := instance_idx;
vvc_labels.channel := channel;
return vvc_labels;
end;
impure function format_msg(
command : t_vvc_cmd_record
) return string is
begin
return add_msg_delimiter(to_string(command.msg)) & " " & format_command_idx(command);
end;
procedure vvc_constructor(
constant scope : in string;
constant instance_idx : in natural;
variable vvc_config : inout t_vvc_config;
variable command_queue : inout work.td_cmd_queue_pkg.t_generic_queue;
variable result_queue : inout work.td_result_queue_pkg.t_generic_queue;
constant bfm_config : in t_bfm_config;
constant cmd_queue_count_max : in natural;
constant cmd_queue_count_threshold : in natural;
constant cmd_queue_count_threshold_severity : in t_alert_level;
constant result_queue_count_max : in natural;
constant result_queue_count_threshold : in natural;
constant result_queue_count_threshold_severity : in t_alert_level
) is
variable v_delta_cycle_counter : natural := 0;
begin
check_value(instance_idx <= C_MAX_VVC_INSTANCE_NUM, TB_FAILURE, "Generic VVC Instance index =" & to_string(instance_idx) &
" cannot exceed C_MAX_VVC_INSTANCE_NUM in UVVM adaptations = " & to_string(C_MAX_VVC_INSTANCE_NUM), C_SCOPE, ID_NEVER);
vvc_config.bfm_config := bfm_config;
vvc_config.cmd_queue_count_max := cmd_queue_count_max;
vvc_config.cmd_queue_count_threshold := cmd_queue_count_threshold;
vvc_config.cmd_queue_count_threshold_severity := cmd_queue_count_threshold_severity;
vvc_config.result_queue_count_max := result_queue_count_max;
vvc_config.result_queue_count_threshold := result_queue_count_threshold;
vvc_config.result_queue_count_threshold_severity := result_queue_count_threshold_severity;
log(ID_CONSTRUCTOR, "VVC instantiated.", scope, vvc_config.msg_id_panel);
command_queue.set_scope(scope & ":cmd_queue");
command_queue.set_queue_count_max(cmd_queue_count_max);
command_queue.set_queue_count_threshold(cmd_queue_count_threshold);
command_queue.set_queue_count_threshold_severity(cmd_queue_count_threshold_severity);
log(ID_CONSTRUCTOR_SUB, "Command queue instantiated with size " & to_string(command_queue.get_queue_count_max(VOID)), command_queue.get_scope(VOID), vvc_config.msg_id_panel);
result_queue.set_scope(scope & ":result_queue");
result_queue.set_queue_count_max(result_queue_count_max);
result_queue.set_queue_count_threshold(result_queue_count_threshold);
result_queue.set_queue_count_threshold_severity(result_queue_count_threshold_severity);
log(ID_CONSTRUCTOR_SUB, "Result queue instantiated with size " & to_string(result_queue.get_queue_count_max(VOID)), result_queue.get_scope(VOID), vvc_config.msg_id_panel);
if shared_uvvm_state /= PHASE_A then
loop
wait for 0 ns;
v_delta_cycle_counter := v_delta_cycle_counter + 1;
exit when shared_uvvm_state = PHASE_A;
check_value((shared_uvvm_state /= IDLE), TB_FAILURE, "UVVM will not work without intitalize_uvvm instantiated as a concurrent procedure in the test harness", scope);
end loop;
end if;
wait; -- show message only once per VVC instance
end procedure;
procedure initialize_interpreter (
signal terminate_current_cmd : out t_flag_record;
signal global_awaiting_completion : out std_logic_vector(C_MAX_NUM_SEQUENCERS-1 downto 0)
) is
begin
terminate_current_cmd <= (set => '0', reset => 'Z', is_active => 'Z'); -- Initialise to avoid undefineds. This process is driving param 1 only.
wait for 0 ns; -- delay by 1 delta cycle to allow constructor to finish first
global_awaiting_completion <= (others => 'Z'); -- Avoid driving until the VVC is involved in await_any_completion()
end procedure;
function broadcast_cmd_to_shared_cmd (
constant broadcast_cmd : t_broadcastable_cmd
) return t_operation is
begin
case broadcast_cmd is
when AWAIT_COMPLETION => return AWAIT_COMPLETION;
when ENABLE_LOG_MSG => return ENABLE_LOG_MSG;
when DISABLE_LOG_MSG => return DISABLE_LOG_MSG;
when FLUSH_COMMAND_QUEUE => return FLUSH_COMMAND_QUEUE;
when INSERT_DELAY => return INSERT_DELAY;
when TERMINATE_CURRENT_COMMAND => return TERMINATE_CURRENT_COMMAND;
when others => return NO_OPERATION;
end case;
end function;
function get_command_type_from_operation (
constant broadcast_cmd : t_broadcastable_cmd
) return t_immediate_or_queued is
begin
case broadcast_cmd is
when AWAIT_COMPLETION => return IMMEDIATE;
when ENABLE_LOG_MSG => return IMMEDIATE;
when DISABLE_LOG_MSG => return IMMEDIATE;
when FLUSH_COMMAND_QUEUE => return IMMEDIATE;
when TERMINATE_CURRENT_COMMAND => return IMMEDIATE;
when INSERT_DELAY => return QUEUED;
when others => return NO_command_type;
end case;
end function;
procedure populate_shared_vvc_cmd_with_broadcast (
variable output_vvc_cmd : out t_vvc_cmd_record
) is
begin
-- Increment the shared command index. This is normally done in the CDM, but for broadcast commands it is done by the VVC itself.
check_value((shared_uvvm_state /= IDLE), TB_FAILURE, "UVVM will not work without uvvm_vvc_framework.ti_uvvm_engine instantiated in the test harness", C_SCOPE, ID_NEVER);
await_semaphore_in_delta_cycles(protected_broadcast_semaphore);
shared_cmd_idx := shared_cmd_idx + 1;
-- Populate the shared VVC command record
output_vvc_cmd.operation := broadcast_cmd_to_shared_cmd(shared_vvc_broadcast_cmd.operation);
output_vvc_cmd.msg_id := shared_vvc_broadcast_cmd.msg_id;
output_vvc_cmd.msg := shared_vvc_broadcast_cmd.msg;
output_vvc_cmd.quietness := shared_vvc_broadcast_cmd.quietness;
output_vvc_cmd.delay := shared_vvc_broadcast_cmd.delay;
output_vvc_cmd.timeout := shared_vvc_broadcast_cmd.timeout;
output_vvc_cmd.gen_integer_array(0) := shared_vvc_broadcast_cmd.gen_integer;
output_vvc_cmd.proc_call := shared_vvc_broadcast_cmd.proc_call;
output_vvc_cmd.cmd_idx := shared_cmd_idx;
output_vvc_cmd.command_type := get_command_type_from_operation(shared_vvc_broadcast_cmd.operation);
if global_show_msg_for_uvvm_cmd then
log(ID_UVVM_SEND_CMD, to_string(shared_vvc_cmd.proc_call) & ": " & add_msg_delimiter(to_string(shared_vvc_cmd.msg)) & "."
& format_command_idx(shared_cmd_idx), C_SCOPE);
else
log(ID_UVVM_SEND_CMD, to_string(shared_vvc_cmd.proc_call)
& format_command_idx(shared_cmd_idx), C_SCOPE);
end if;
release_semaphore(protected_broadcast_semaphore);
end procedure;
procedure await_cmd_from_sequencer(
constant vvc_labels : in t_vvc_labels;
constant vvc_config : in t_vvc_config;
signal VVCT : in t_vvc_target_record;
signal VVC_BROADCAST : inout std_logic;
signal global_vvc_busy : inout std_logic;
signal vvc_ack : out std_logic;
constant shared_vvc_cmd : in t_vvc_cmd_record;
variable output_vvc_cmd : out t_vvc_cmd_record
) is
variable v_was_broadcast : boolean := false;
begin
vvc_ack <= 'Z'; -- Do not contribute to the acknowledge unless selected
-- Wait for a new command
log(ID_CMD_INTERPRETER_WAIT, "Interpreter: Waiting for command", to_string(vvc_labels.scope) , vvc_config.msg_id_panel);
loop
VVC_BROADCAST <= 'Z';
global_vvc_busy <= 'L';
wait until (VVCT.trigger = '1' or VVC_BROADCAST = '1');
if VVC_BROADCAST'event and VVC_BROADCAST = '1' then
v_was_broadcast := true;
VVC_BROADCAST <= '1';
populate_shared_vvc_cmd_with_broadcast(output_vvc_cmd);
else
-- set VVC_BROADCAST to 0 to force a broadcast to wait for that VVC
VVC_BROADCAST <= '0';
global_vvc_busy <= '1';
-- copy shared_vvc_cmd to release the semaphore
output_vvc_cmd := shared_vvc_cmd;
end if;
-- Check that the channel is valid
if (not v_was_broadcast) then
if (VVCT.vvc_instance_idx = vvc_labels.instance_idx and
VVCT.vvc_name(1 to valid_length(vvc_labels.vvc_name)) = vvc_labels.vvc_name(1 to valid_length(vvc_labels.vvc_name))) then
if ((VVCT.vvc_channel = NA and vvc_labels.channel /= NA) or
(vvc_labels.channel = NA and (VVCT.vvc_channel /= NA and VVCT.vvc_channel /= ALL_CHANNELS))) then
tb_warning(to_string(output_vvc_cmd.proc_call) & " Channel "& to_string(VVCT.vvc_channel) & " not supported on this VVC " & format_command_idx(output_vvc_cmd), to_string(vvc_labels.scope));
-- only release semaphore and stay in loop forcing a timeout too
release_semaphore(protected_semaphore);
end if;
end if;
end if;
exit when (v_was_broadcast or -- Broadcast, or
(((VVCT.vvc_instance_idx = vvc_labels.instance_idx) or (VVCT.vvc_instance_idx = ALL_INSTANCES)) and -- Index is correct or broadcast index
((VVCT.vvc_channel = ALL_CHANNELS) or (VVCT.vvc_channel = vvc_labels.channel)) and -- Channel is correct or broadcast channel
VVCT.vvc_name(1 to valid_length(vvc_labels.vvc_name)) = vvc_labels.vvc_name(1 to valid_length(vvc_labels.vvc_name)))); -- Name is correct
end loop;
if ((VVCT.vvc_instance_idx = ALL_INSTANCES) or (VVCT.vvc_channel = ALL_CHANNELS) ) then
-- in case of a multicast block the global acknowledge until all vvc receiving the message processed it
vvc_ack <= '0';
end if;
wait for 0 ns;
if not v_was_broadcast then
-- release the semaphore if it was not a broadcast
release_semaphore(protected_semaphore);
end if;
log(ID_CMD_INTERPRETER, to_string(output_vvc_cmd.proc_call) & ". Command received " & format_command_idx(output_vvc_cmd), vvc_labels.scope, vvc_config.msg_id_panel); -- Get and ack the new command
end procedure;
procedure put_command_on_queue(
constant command : in t_vvc_cmd_record;
variable command_queue : inout work.td_cmd_queue_pkg.t_generic_queue;
variable vvc_status : inout t_vvc_status;
signal queue_is_increasing : out boolean
) is
begin
command_queue.put(command);
vvc_status.pending_cmd_cnt := command_queue.get_count(VOID);
queue_is_increasing <= true;
wait for 0 ns;
queue_is_increasing <= false;
end procedure;
procedure interpreter_await_completion(
constant command : in t_vvc_cmd_record;
variable command_queue : inout work.td_cmd_queue_pkg.t_generic_queue;
constant vvc_config : in t_vvc_config;
signal executor_is_busy : in boolean;
constant vvc_labels : in t_vvc_labels;
signal last_cmd_idx_executed : in natural;
constant await_completion_pending_msg_id : in t_msg_id := ID_IMMEDIATE_CMD_WAIT;
constant await_completion_finished_msg_id : in t_msg_id := ID_IMMEDIATE_CMD
) is
alias wanted_idx : integer is command.gen_integer_array(0); -- generic integer used as wanted command idx to wait for
begin
if wanted_idx = -1 then
-- await completion of all commands
if not command_queue.is_empty(VOID) or executor_is_busy then
log(await_completion_pending_msg_id, "await_completion() - Pending completion " & to_string(command.msg) & " " & format_command_idx(command), to_string(vvc_labels.scope), vvc_config.msg_id_panel); -- Get and ack the new command
loop
if command.timeout = 0 ns then
wait until executor_is_busy = false;
else
wait until (executor_is_busy = false) for command.timeout;
end if;
if command_queue.is_empty(VOID) or not executor_is_busy'event then
exit;
end if;
end loop;
end if;
log(await_completion_finished_msg_id, "await_completion() => Finished. " & to_string(command.msg) & " " & format_command_idx(command), to_string(vvc_labels.scope), vvc_config.msg_id_panel); -- Get and ack the new command
else -- await specific instruction
if last_cmd_idx_executed < wanted_idx then
log(await_completion_pending_msg_id, "await_completion(" & to_string(wanted_idx) & ") - Pending selected " & to_string(command.msg) & " " & format_command_idx(command), to_string(vvc_labels.scope), vvc_config.msg_id_panel); -- Get and ack the new command
loop
if command.timeout = 0 ns then
wait until executor_is_busy = false;
else
wait until executor_is_busy = false for command.timeout;
end if;
if last_cmd_idx_executed >= wanted_idx or not executor_is_busy'event then
exit;
end if;
end loop;
end if;
log(await_completion_finished_msg_id, "await_completion(" & to_string(wanted_idx) & ") => Finished. " & to_string(command.msg) & " " & format_command_idx(command), to_string(vvc_labels.scope), vvc_config.msg_id_panel); -- Get & ack the new command
end if;
end procedure;
------------------------------------------------------------------------------------------
-- Wait for any of the following :
-- await_completion of this VVC, or
-- until global_awaiting_completion /= '1' (any of the other involved VVCs completed).
------------------------------------------------------------------------------------------
procedure interpreter_await_any_completion(
constant command : in t_vvc_cmd_record;
variable command_queue : inout work.td_cmd_queue_pkg.t_generic_queue;
constant vvc_config : in t_vvc_config;
signal executor_is_busy : in boolean;
constant vvc_labels : in t_vvc_labels;
signal last_cmd_idx_executed : in natural;
signal global_awaiting_completion : inout std_logic_vector; -- Handshake from other VVCs performing await_any_completion
constant await_completion_pending_msg_id : in t_msg_id := ID_IMMEDIATE_CMD_WAIT;
constant await_completion_finished_msg_id : in t_msg_id := ID_IMMEDIATE_CMD
) is
alias wanted_idx : integer is command.gen_integer_array(0); -- generic integer used as wanted command idx to wait for
alias awaiting_completion_idx : integer is command.gen_integer_array(1); -- generic integer used as awaiting_completion_idx
variable v_done : boolean := false; -- Whether we're done waiting
-----------------------------------------------
-- Local function
-- Return whether if this VVC has completed
-----------------------------------------------
impure function this_vvc_completed (
dummy : t_void
) return boolean is
begin
if wanted_idx = -1 then
-- All commands must be completed (i.e. not just a selected command index)
return (executor_is_busy = false and command_queue.is_empty(VOID));
else
-- await a SPECIFIC command in this VVC
return (last_cmd_idx_executed >= wanted_idx);
end if;
end;
begin
--
-- Signal that this VVC is participating in the await_any_completion group by driving global_awaiting_completion
--
if not command.gen_boolean then -- NOT_LAST
-- If this is a NOT_LAST call: Wait for delta cycles until the LAST call sets it to '1',
-- then set it to '1' here.
-- Purpose of waiting : synchronize the LAST VVC with all the NOT_LAST VVCs, so that it doesn't have to wait a magic number of delta cycles
while global_awaiting_completion(awaiting_completion_idx) = 'Z' loop
wait for 0 ns;
end loop;
global_awaiting_completion(awaiting_completion_idx) <= '1';
else
-- If this is a LAST call: Set to '1' for at least one delta cycle, so that all NOT_LAST calls detects it.
global_awaiting_completion(awaiting_completion_idx) <= '1';
wait for 0 ns;
end if;
-- This VVC already completed?
if this_vvc_completed(VOID) then
v_done := true;
end if;
-- Any of the other involved VVCs already completed?
if (global_awaiting_completion(awaiting_completion_idx) = 'X' or global_awaiting_completion(awaiting_completion_idx) = '0') then
v_done := true;
end if;
if not v_done then
-- Start waiting for the first of this VVC or other VVC
log(await_completion_pending_msg_id, to_string(command.proc_call) & " - Pending completion " & to_string(command.msg) & " " & format_command_idx(command), to_string(vvc_labels.scope), vvc_config.msg_id_panel);
loop
wait until ((executor_is_busy = false) or (global_awaiting_completion(awaiting_completion_idx) /= '1')) for command.timeout;
if this_vvc_completed(VOID) or -- This VVC is done
global_awaiting_completion(awaiting_completion_idx) = '0' or -- All other involved VVCs are done
global_awaiting_completion(awaiting_completion_idx) = 'X' then -- Some other involved VVCs are done
exit;
end if;
if not ((executor_is_busy'event) or (global_awaiting_completion(awaiting_completion_idx) /= '1')) then -- Indicates timeout
-- When NOT_LAST (command.gen_boolean = false): Timeout must be reported here instead of in send_command_to_vvc()
-- becuase the command is always acknowledged immediately by the VVC to allow the sequencer to continue
if not command.gen_boolean then
tb_error("Timeout during " & to_string(command.proc_call) & "=> " & format_msg(command), to_string(vvc_labels.scope));
end if;
exit;
end if;
end loop;
end if;
global_awaiting_completion(awaiting_completion_idx) <= '0'; -- Signal that we're done waiting
-- Handshake : Wait until every involved VVC notice the value is 'X' or '0', and all agree to being done ('0')
if global_awaiting_completion(awaiting_completion_idx) /= '0' then
wait until (global_awaiting_completion(awaiting_completion_idx) = '0');
end if;
global_awaiting_completion(awaiting_completion_idx) <= 'Z'; -- Idle
log(await_completion_finished_msg_id, to_string(command.proc_call) & "=> Finished. " & format_msg(command), to_string(vvc_labels.scope), vvc_config.msg_id_panel); -- Get & ack the new command
end procedure;
procedure interpreter_flush_command_queue(
constant command : in t_vvc_cmd_record;
variable command_queue : inout work.td_cmd_queue_pkg.t_generic_queue;
constant vvc_config : in t_vvc_config;
variable vvc_status : inout t_vvc_status;
constant vvc_labels : in t_vvc_labels
) is
begin
log(ID_IMMEDIATE_CMD, "Flushing command queue (" & to_string(shared_vvc_cmd.gen_integer_array(0)) & ") " & format_command_idx(shared_vvc_cmd), to_string(vvc_labels.scope), vvc_config.msg_id_panel);
command_queue.flush(VOID);
vvc_status.pending_cmd_cnt := command_queue.get_count(VOID);
end;
procedure interpreter_terminate_current_command(
constant command : in t_vvc_cmd_record;
constant vvc_config : in t_vvc_config;
constant vvc_labels : in t_vvc_labels;
signal terminate_current_cmd : inout t_flag_record
) is
begin
log(ID_IMMEDIATE_CMD, "Terminating command in executor", to_string(vvc_labels.scope), vvc_config.msg_id_panel);
set_flag(terminate_current_cmd);
end procedure;
procedure interpreter_fetch_result(
variable result_queue : inout work.td_result_queue_pkg.t_generic_queue;
constant command : in t_vvc_cmd_record;
constant vvc_config : in t_vvc_config;
constant vvc_labels : in t_vvc_labels;
constant last_cmd_idx_executed : in natural;
variable shared_vvc_response : inout work.vvc_cmd_pkg.t_vvc_response
) is
variable v_current_element : work.vvc_cmd_pkg.t_vvc_result_queue_element;
variable v_local_result_queue : work.td_result_queue_pkg.t_generic_queue;
begin
v_local_result_queue.set_scope(to_string(vvc_labels.scope));
shared_vvc_response.fetch_is_accepted := false; -- default
if last_cmd_idx_executed < command.gen_integer_array(0) then
tb_warning(to_string(command.proc_call) & ". Requested result is not yet available. " & format_command_idx(command), to_string(vvc_labels.scope));
else
-- Search for the command idx among the elements of the queue.
-- Easiest method of doing this is to pop elements, and pushing them again
-- if the cmd idx does not match. Not very efficient, but an OK initial implementation.
-- Pop the element. Compare cmd idx. If it does not match, push to local result queue.
-- If an index matches, set shared_vvc_response.result. (Don't push element back to result queue)
while result_queue.get_count(VOID) > 0 loop
v_current_element := result_queue.get(VOID);
if v_current_element.cmd_idx = command.gen_integer_array(0) then
shared_vvc_response.fetch_is_accepted := true;
shared_vvc_response.result := v_current_element.result;
log(ID_IMMEDIATE_CMD, to_string(command.proc_call) & " Requested result is found" & ". " & to_string(command.msg) & " " & format_command_idx(command), to_string(vvc_labels.scope), vvc_config.msg_id_panel); -- Get and ack the new command
exit;
else
-- No match for element: put in local result queue
v_local_result_queue.put(v_current_element);
end if;
end loop;
-- Pop each element of local result queue and push to result queue.
-- This is to clear the local result queue and restore the result
-- queue to its original state (except that the matched element is not put back).
while v_local_result_queue.get_count(VOID) > 0 loop
result_queue.put(v_local_result_queue.get(VOID));
end loop;
if not shared_vvc_response.fetch_is_accepted then
tb_warning(to_string(command.proc_call) & ". Requested result was not found. Given command index is not available in this VVC. " & format_command_idx(command), to_string(vvc_labels.scope));
end if;
end if;
end procedure;
procedure initialize_executor (
signal terminate_current_cmd : inout t_flag_record
) is
begin
reset_flag(terminate_current_cmd);
wait for 0 ns; -- delay by 1 delta cycle to allow constructor to finish first
end procedure;
procedure fetch_command_and_prepare_executor(
variable command : inout t_vvc_cmd_record;
variable command_queue : inout work.td_cmd_queue_pkg.t_generic_queue;
constant vvc_config : in t_vvc_config;
variable vvc_status : inout t_vvc_status;
signal queue_is_increasing : in boolean;
signal executor_is_busy : inout boolean;
constant vvc_labels : in t_vvc_labels
) is
begin
executor_is_busy <= false;
wait for 0 ns; -- to allow delta updates in other processes.
if command_queue.is_empty(VOID) then
log(ID_CMD_EXECUTOR_WAIT, "Executor: Waiting for command", to_string(vvc_labels.scope), vvc_config.msg_id_panel);
wait until queue_is_increasing;
end if;
-- Queue is now not empty
executor_is_busy <= true;
wait until executor_is_busy;
vvc_status.previous_cmd_idx := command.cmd_idx;
command := command_queue.get(VOID);
log(ID_CMD_EXECUTOR, to_string(command.proc_call) & " - Will be executed " & format_command_idx(command), to_string(vvc_labels.scope), vvc_config.msg_id_panel); -- Get and ack the new command
vvc_status.pending_cmd_cnt := command_queue.get_count(VOID);
vvc_status.current_cmd_idx := command.cmd_idx;
end procedure;
-- The result_queue is used so that whatever type defined in the VVC can be stored,
-- and later fetched with fetch_result()
procedure store_result(
variable result_queue : inout work.td_result_queue_pkg.t_generic_queue;
constant cmd_idx : in natural;
constant result : in t_vvc_result
) is
variable v_result_queue_element : t_vvc_result_queue_element;
begin
v_result_queue_element.cmd_idx := cmd_idx;
v_result_queue_element.result := result;
result_queue.put(v_result_queue_element);
end procedure;
procedure insert_inter_bfm_delay_if_requested(
constant vvc_config : in t_vvc_config;
constant command_is_bfm_access : in boolean;
constant timestamp_start_of_last_bfm_access : in time;
constant timestamp_end_of_last_bfm_access : in time;
constant scope : in string := C_SCOPE
) is
begin
-- If both timestamps are at 0 ns we interpret this as the first BFM access, hence no delay shall be applied.
if ((vvc_config.inter_bfm_delay.delay_type /= NO_DELAY) and
command_is_bfm_access and
not ((timestamp_start_of_last_bfm_access = 0 ns) and (timestamp_end_of_last_bfm_access = 0 ns))) then
case vvc_config.inter_bfm_delay.delay_type is
when TIME_FINISH2START =>
if now < (timestamp_end_of_last_bfm_access + vvc_config.inter_bfm_delay.delay_in_time) then
log(ID_INSERTED_DELAY, "Delaying BFM access until time " & to_string(timestamp_end_of_last_bfm_access + vvc_config.inter_bfm_delay.delay_in_time)
& ".", scope, vvc_config.msg_id_panel);
wait for (timestamp_end_of_last_bfm_access + vvc_config.inter_bfm_delay.delay_in_time - now);
end if;
when TIME_START2START =>
if now < (timestamp_start_of_last_bfm_access + vvc_config.inter_bfm_delay.delay_in_time) then
log(ID_INSERTED_DELAY, "Delaying BFM access until time " & to_string(timestamp_start_of_last_bfm_access + vvc_config.inter_bfm_delay.delay_in_time)
& ".", scope, vvc_config.msg_id_panel);
wait for (timestamp_start_of_last_bfm_access + vvc_config.inter_bfm_delay.delay_in_time - now);
end if;
when others =>
tb_error("Delay type " & to_upper(to_string(vvc_config.inter_bfm_delay.delay_type)) & " not supported for this VVC.", C_SCOPE);
end case;
log(ID_INSERTED_DELAY, "Finished delaying BFM access", scope, vvc_config.msg_id_panel);
end if;
end procedure;
end package body td_vvc_entity_support_pkg;
xxxxxxxxxx
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
-- IYHT: add the context clause to use the util clock generator
library uvvm_vvc_framework;
use uvvm_vvc_framework.ti_vvc_framework_support_pkg.all;
--library vip_counter;
-- Test harness entity
entity counter_vvc_th is
end entity;
-- Test harness architecture
architecture struct of counter_vvc_th is
-- general control signals
signal clk : std_logic := '0';
-- counter VVC signals
signal Reset, Enable, Load, UpDn: Std_logic;
signal Data, Q: Std_logic_vector(7 downto 0);
constant C_CLK_PERIOD : time := 5 ns; -- 200 MHz
begin
-----------------------------------------------------------------------------
-- Instantiate the concurrent procedure that initializes UVVM
-----------------------------------------------------------------------------
i_ti_uvvm_engine : entity uvvm_vvc_framework.ti_uvvm_engine;
-----------------------------------------------------------------------------
-- Instantiate DUT
-----------------------------------------------------------------------------
i_counter: entity work.counter
port map (
-- general control signals
Clock => clk,
-- counter signals
Reset => Reset,
Enable => Enable,
Load => Load,
UpDn => UpDn,
Data => Data,
Q => Q
);
-----------------------------------------------------------------------------
-- counter VVC
-----------------------------------------------------------------------------
i_counter_vvc: entity work.counter_vvc
generic map(
GC_DATA_WIDTH => 8,
GC_INSTANCE_IDX => 1
)
port map(
clk => clk,
counter_vvc_if.Reset => Reset,
counter_vvc_if.Enable => Enable,
counter_vvc_if.Load => Load,
counter_vvc_if.UpDn => UpDn,
counter_vvc_if.Data => Data,
counter_vvc_if.Q => Q
);
-----------------------------------------------------------------------------
-- Clock process
-----------------------------------------------------------------------------
p_clk: process
begin
clk <= '0', '1' after C_CLK_PERIOD / 2;
wait for C_CLK_PERIOD;
end process;
-- IYHT: use the util clock generator
end struct;
xxxxxxxxxx
--========================================================================================================================
-- This VVC was generated with Bitvis VVC Generator
--========================================================================================================================
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library uvvm_util;
context uvvm_util.uvvm_util_context;
library uvvm_vvc_framework;
use uvvm_vvc_framework.ti_vvc_framework_support_pkg.all;
use work.counter_bfm_pkg.all;
use work.vvc_methods_pkg.all;
use work.vvc_cmd_pkg.all;
use work.td_target_support_pkg.all;
use work.td_vvc_entity_support_pkg.all;
use work.td_cmd_queue_pkg.all;
use work.td_result_queue_pkg.all;
--========================================================================================================================
entity counter_vvc is
generic (
--<USER_INPUT> Insert interface specific generic constants here
GC_DATA_WIDTH : integer range 1 to C_VVC_CMD_DATA_MAX_LENGTH;
GC_INSTANCE_IDX : natural;
GC_COUNTER_BFM_CONFIG : t_counter_bfm_config := C_COUNTER_BFM_CONFIG_DEFAULT;
GC_CMD_QUEUE_COUNT_MAX : natural := 1000;
GC_CMD_QUEUE_COUNT_THRESHOLD : natural := 950;
GC_CMD_QUEUE_COUNT_THRESHOLD_SEVERITY : t_alert_level := WARNING;
GC_RESULT_QUEUE_COUNT_MAX : natural := 1000;
GC_RESULT_QUEUE_COUNT_THRESHOLD : natural := 950;
GC_RESULT_QUEUE_COUNT_THRESHOLD_SEVERITY : t_alert_level := WARNING
);
port (
--<USER_INPUT> Insert BFM interface signals here
counter_vvc_if : inout t_counter_if := init_counter_if_signals( GC_DATA_WIDTH);
-- VVC control signals:
-- rst : in std_logic; -- Optional VVC Reset
clk : in std_logic
);
end entity counter_vvc;
--========================================================================================================================
--========================================================================================================================
architecture behave of counter_vvc is
constant C_SCOPE : string := C_VVC_NAME & "," & to_string(GC_INSTANCE_IDX);
constant C_VVC_LABELS : t_vvc_labels := assign_vvc_labels(C_SCOPE, C_VVC_NAME, GC_INSTANCE_IDX, NA);
signal executor_is_busy : boolean := false;
signal queue_is_increasing : boolean := false;
signal last_cmd_idx_executed : natural := 0;
signal terminate_current_cmd : t_flag_record;
-- Instantiation of the element dedicated Queue
shared variable command_queue : work.td_cmd_queue_pkg.t_generic_queue;
shared variable result_queue : work.td_result_queue_pkg.t_generic_queue;
alias vvc_config : t_vvc_config is shared_counter_vvc_config(GC_INSTANCE_IDX);
alias vvc_status : t_vvc_status is shared_counter_vvc_status(GC_INSTANCE_IDX);
alias transaction_info : t_transaction_info is shared_counter_transaction_info(GC_INSTANCE_IDX);
begin
--========================================================================================================================
-- Constructor
-- - Set up the defaults and show constructor if enabled
--========================================================================================================================
work.td_vvc_entity_support_pkg.vvc_constructor(C_SCOPE, GC_INSTANCE_IDX, vvc_config, command_queue, result_queue, GC_COUNTER_BFM_CONFIG,
GC_CMD_QUEUE_COUNT_MAX, GC_CMD_QUEUE_COUNT_THRESHOLD, GC_CMD_QUEUE_COUNT_THRESHOLD_SEVERITY,
GC_RESULT_QUEUE_COUNT_MAX, GC_RESULT_QUEUE_COUNT_THRESHOLD, GC_RESULT_QUEUE_COUNT_THRESHOLD_SEVERITY);
--========================================================================================================================
--========================================================================================================================
-- Command interpreter
-- - Interpret, decode and acknowledge commands from the central sequencer
--========================================================================================================================
cmd_interpreter : process
variable v_cmd_has_been_acked : boolean; -- Indicates if acknowledge_cmd() has been called for the current shared_vvc_cmd
variable v_local_vvc_cmd : t_vvc_cmd_record := C_VVC_CMD_DEFAULT;
begin
-- 0. Initialize the process prior to first command
work.td_vvc_entity_support_pkg.initialize_interpreter(terminate_current_cmd, global_awaiting_completion);
-- initialise shared_vvc_last_received_cmd_idx for channel and instance
shared_vvc_last_received_cmd_idx(NA, GC_INSTANCE_IDX) := 0;
-- Then for every single command from the sequencer
loop -- basically as long as new commands are received
-- 1. wait until command targeted at this VVC. Must match VVC name, instance and channel (if applicable)
-- releases global semaphore
-------------------------------------------------------------------------
work.td_vvc_entity_support_pkg.await_cmd_from_sequencer(C_VVC_LABELS, vvc_config, THIS_VVCT, VVC_BROADCAST, global_vvc_busy, global_vvc_ack, shared_vvc_cmd, v_local_vvc_cmd);
v_cmd_has_been_acked := false; -- Clear flag
-- update shared_vvc_last_received_cmd_idx with received command index
shared_vvc_last_received_cmd_idx(NA, GC_INSTANCE_IDX) := v_local_vvc_cmd.cmd_idx;
-- 2a. Put command on the queue if intended for the executor
-------------------------------------------------------------------------
if v_local_vvc_cmd.command_type = QUEUED then
work.td_vvc_entity_support_pkg.put_command_on_queue(v_local_vvc_cmd, command_queue, vvc_status, queue_is_increasing);
-- 2b. Otherwise command is intended for immediate response
-------------------------------------------------------------------------
elsif v_local_vvc_cmd.command_type = IMMEDIATE then
case v_local_vvc_cmd.operation is
when AWAIT_COMPLETION =>
-- Await completion of all commands in the cmd_executor queue
work.td_vvc_entity_support_pkg.interpreter_await_completion(v_local_vvc_cmd, command_queue, vvc_config, executor_is_busy, C_VVC_LABELS, last_cmd_idx_executed);
when AWAIT_ANY_COMPLETION =>
if not v_local_vvc_cmd.gen_boolean then
-- Called with lastness = NOT_LAST: Acknowledge immediately to let the sequencer continue
work.td_target_support_pkg.acknowledge_cmd(global_vvc_ack,v_local_vvc_cmd.cmd_idx);
v_cmd_has_been_acked := true;
end if;
work.td_vvc_entity_support_pkg.interpreter_await_any_completion(v_local_vvc_cmd, command_queue, vvc_config, executor_is_busy, C_VVC_LABELS, last_cmd_idx_executed, global_awaiting_completion);
when DISABLE_LOG_MSG =>
uvvm_util.methods_pkg.disable_log_msg(v_local_vvc_cmd.msg_id, vvc_config.msg_id_panel, to_string(v_local_vvc_cmd.msg) & format_command_idx(v_local_vvc_cmd), C_SCOPE, v_local_vvc_cmd.quietness);
when ENABLE_LOG_MSG =>
uvvm_util.methods_pkg.enable_log_msg(v_local_vvc_cmd.msg_id, vvc_config.msg_id_panel, to_string(v_local_vvc_cmd.msg) & format_command_idx(v_local_vvc_cmd), C_SCOPE, v_local_vvc_cmd.quietness);
when FLUSH_COMMAND_QUEUE =>
work.td_vvc_entity_support_pkg.interpreter_flush_command_queue(v_local_vvc_cmd, command_queue, vvc_config, vvc_status, C_VVC_LABELS);
when TERMINATE_CURRENT_COMMAND =>
work.td_vvc_entity_support_pkg.interpreter_terminate_current_command(v_local_vvc_cmd, vvc_config, C_VVC_LABELS, terminate_current_cmd);
-- when FETCH_RESULT =>
-- work.td_vvc_entity_support_pkg.interpreter_fetch_result(result_queue, v_local_vvc_cmd, vvc_config, C_VVC_LABELS, last_cmd_idx_executed, shared_vvc_response);
when others =>
tb_error("Unsupported command received for IMMEDIATE execution: '" & to_string(v_local_vvc_cmd.operation) & "'", C_SCOPE);
end case;
else
tb_error("command_type is not IMMEDIATE or QUEUED", C_SCOPE);
end if;
-- 3. Acknowledge command after runing or queuing the command
-------------------------------------------------------------------------
if not v_cmd_has_been_acked then
work.td_target_support_pkg.acknowledge_cmd(global_vvc_ack,v_local_vvc_cmd.cmd_idx);
end if;
end loop;
end process;
--========================================================================================================================
--========================================================================================================================
-- Command executor
-- - Fetch and execute the commands
--========================================================================================================================
cmd_executor : process
variable v_cmd : t_vvc_cmd_record;
--variable v_Q : t_vvc_result; -- See vvc_cmd_pkg
variable v_timestamp_start_of_current_bfm_access : time := 0 ns;
variable v_timestamp_start_of_last_bfm_access : time := 0 ns;
variable v_timestamp_end_of_last_bfm_access : time := 0 ns;
variable v_command_is_bfm_access : boolean;
variable v_normalised_data : std_logic_vector(GC_DATA_WIDTH-1 downto 0) := (others => '0');
variable v_normalised_Q : std_logic_vector(GC_DATA_WIDTH-1 downto 0) := (others => '0');
variable v_normalised_cycles : natural;
begin
-- 0. Initialize the process prior to first command
-------------------------------------------------------------------------
work.td_vvc_entity_support_pkg.initialize_executor(terminate_current_cmd);
loop
-- 1. Set defaults, fetch command and log
-------------------------------------------------------------------------
work.td_vvc_entity_support_pkg.fetch_command_and_prepare_executor(v_cmd, command_queue, vvc_config, vvc_status, queue_is_increasing, executor_is_busy, C_VVC_LABELS);
-- Reset the transaction info for waveview
transaction_info := C_TRANSACTION_INFO_DEFAULT;
transaction_info.operation := v_cmd.operation;
transaction_info.msg := pad_string(to_string(v_cmd.msg), ' ', transaction_info.msg'length);
-- Check if command is a BFM access
--<USER_INPUT> Replace this if statement with a check of the current v_cmd.operation, in order to set v_cmd_is_bfm_access to true if this is a BFM access command
if v_cmd.operation = RESET or v_cmd.operation = LOAD or v_cmd.operation = CHECK or v_cmd.operation = COUNT_UP or v_cmd.operation = HOLD then
v_command_is_bfm_access := true; -- IYHT: check counting down
else
v_command_is_bfm_access := false;
end if;
-- Insert delay if needed
work.td_vvc_entity_support_pkg.insert_inter_bfm_delay_if_requested(vvc_config => vvc_config,
command_is_bfm_access => v_command_is_bfm_access,
timestamp_start_of_last_bfm_access => v_timestamp_start_of_last_bfm_access,
timestamp_end_of_last_bfm_access => v_timestamp_end_of_last_bfm_access,
scope => C_SCOPE);
if v_command_is_bfm_access then
v_timestamp_start_of_current_bfm_access := now;
end if;
-- 2. Execute the fetched command
-------------------------------------------------------------------------
case v_cmd.operation is -- Only operations in the dedicated record are relevant
-- VVC dedicated operations
--===================================
--<USER_INPUT>: Insert BFM procedure calls here
when RESET =>
-- Call the corresponding procedure in the BFM package.
counter_reset(msg => format_msg(v_cmd),
clk => clk,
counter_if => counter_vvc_if,
scope => C_SCOPE,
msg_id_panel => vvc_config.msg_id_panel,
config => vvc_config.bfm_config);
-- Add info to the transaction_for_waveview_struct if needed
--transaction_info.reset := true;
-- If the result from the BFM call is to be stored, e.g. in a read call, use the additional procedure illustrated in this read example
when CHECK =>
v_normalised_Q := normalize_and_check(v_cmd.Q, v_normalised_Q, ALLOW_WIDER_NARROWER, "Q", "shared_vvc_cmd.Q", "counter_check() called with too wide Q. " & v_cmd.msg);
-- Add info to the transaction_for_waveview_struct if needed
transaction_info.Q(GC_DATA_WIDTH - 1 downto 0) := v_normalised_Q;
-- Call the corresponding procedure in the BFM package.
counter_check(Q_exp => v_normalised_Q,
msg => format_msg(v_cmd),
clk => clk,
counter_if => counter_vvc_if,
scope => C_SCOPE,
msg_id_panel => vvc_config.msg_id_panel,
config => vvc_config.bfm_config);
when LOAD =>
v_normalised_data := normalize_and_check(v_cmd.data, v_normalised_data, ALLOW_WIDER_NARROWER, "data", "shared_vvc_cmd.data", "counter_load() called with too wide data. " & v_cmd.msg);
-- Add info to the transaction_for_waveview_struct if needed
transaction_info.data(GC_DATA_WIDTH - 1 downto 0) := v_normalised_data;
-- Call the corresponding procedure in the BFM package.
counter_load(data_value=> v_normalised_data,
msg => format_msg(v_cmd),
clk => clk,
counter_if => counter_vvc_if,
scope => C_SCOPE,
msg_id_panel => vvc_config.msg_id_panel,
config => vvc_config.bfm_config);
when COUNT_UP =>
-- Add info to the transaction_for_waveview_struct if needed
transaction_info.cycles := v_cmd.cycles;
-- Call the corresponding procedure in the BFM package.
counter_count_up(
cycles => v_cmd.cycles,
msg => format_msg(v_cmd),
clk => clk,
counter_if => counter_vvc_if,
scope => C_SCOPE,
msg_id_panel => vvc_config.msg_id_panel,
config => vvc_config.bfm_config);
-- IYHT: check counting down
when HOLD =>
-- Add info to the transaction_for_waveview_struct if needed
transaction_info.cycles := v_cmd.cycles;
-- Call the corresponding procedure in the BFM package.
counter_hold(
cycles => v_cmd.cycles,
msg => format_msg(v_cmd),
clk => clk,
counter_if => counter_vvc_if,
scope => C_SCOPE,
msg_id_panel => vvc_config.msg_id_panel,
config => vvc_config.bfm_config);
-- UVVM common operations
--===================================
when INSERT_DELAY =>
log(ID_INSERTED_DELAY, "Running: " & to_string(v_cmd.proc_call) & " " & format_command_idx(v_cmd), C_SCOPE, vvc_config.msg_id_panel);
if v_cmd.gen_integer_array(0) = -1 then
-- Delay specified using time
wait until terminate_current_cmd.is_active = '1' for v_cmd.delay;
else
-- Delay specified using integer
wait until terminate_current_cmd.is_active = '1' for v_cmd.gen_integer_array(0) * vvc_config.bfm_config.clock_period;
end if;
when others =>
tb_error("Unsupported local command received for execution: '" & to_string(v_cmd.operation) & "'", C_SCOPE);
end case;
if v_command_is_bfm_access then
v_timestamp_end_of_last_bfm_access := now;
v_timestamp_start_of_last_bfm_access := v_timestamp_start_of_current_bfm_access;
if ((vvc_config.inter_bfm_delay.delay_type = TIME_START2START) and
((now - v_timestamp_start_of_current_bfm_access) > vvc_config.inter_bfm_delay.delay_in_time)) then
alert(vvc_config.inter_bfm_delay.inter_bfm_delay_violation_severity, "BFM access exceeded specified start-to-start inter-bfm delay, " &
to_string(vvc_config.inter_bfm_delay.delay_in_time) & ".", C_SCOPE);
end if;
end if;
-- Reset terminate flag if any occurred
if (terminate_current_cmd.is_active = '1') then
log(ID_CMD_EXECUTOR, "Termination request received", C_SCOPE, vvc_config.msg_id_panel);
uvvm_vvc_framework.ti_vvc_framework_support_pkg.reset_flag(terminate_current_cmd);
end if;
last_cmd_idx_executed <= v_cmd.cmd_idx;
-- Reset the transaction info for waveview
transaction_info := C_TRANSACTION_INFO_DEFAULT;
end loop;
end process;
--========================================================================================================================
--========================================================================================================================
-- Command termination handler
-- - Handles the termination request record (sets and resets terminate flag on request)
--========================================================================================================================
cmd_terminator : uvvm_vvc_framework.ti_vvc_framework_support_pkg.flag_handler(terminate_current_cmd); -- flag: is_active, set, reset
--========================================================================================================================
end behave;
library IEEE;
use IEEE.Std_logic_1164.all;
use IEEE.Numeric_std.all;
entity Counter is
port (Clock, Reset, Enable, Load, UpDn: in Std_logic;
Data: in Std_logic_vector(7 downto 0);
Q: out Std_logic_vector(7 downto 0));
end;
architecture RTL of Counter is
signal Cnt: Unsigned(7 downto 0);
begin
process (Clock, Reset)
begin
if Reset = '1' then
Cnt <= (others => '0');
elsif Rising_edge(Clock) then
if Enable = '1' then
if Load = '1' then
Cnt <= Unsigned(Data);
elsif UpDn = '1' then
Cnt <= Cnt + 1;
else
Cnt <= Cnt - 1;
end if;
end if;
end if;
end process;
Q <= Std_logic_vector(Cnt);
end;
Your account is not validated. If you wish to use commercial simulators, you need a validated account.
If you have already registered (or have recently changed your email address), but have not clicked on the link in the email we sent you, please do so. If you cannot find the email, please check your spam/junk folder. Or click here to resend the email.
If you have not already registered for a full account, you can do so by clicking below. You will then need to provide us with some identification information. You may wish to save your code first.
Creating, deleting, and renaming files is not supported during Collaboration. To encourage development of these features for Collaboration, tweet to @EDAPlayground
This playground may have been modified. Please save or copy before starting collaboration.
Your exercise has been submitted.