GeezerVisonThe World Wide Web, restored to 800 pixels of glory. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Home|About|Gaming cabinet|Archives|How it works|Starter sites | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
GeezerVison is showing uvvm.github.io — VVC Framework — UVVM documentation VVC FrameworkThe VVC Framework allows you to control your complete testbench architecture with any number of verification components. By executing the commands from the test case sequencer, the VVCs can be controlled (via global signals and shared variables transparent to the user) to generate and receive data from the DUT, thus giving a more structured and easier to control testbench. A structured test environment is important, and we recommend the use of a structured test harness to instantiate VVCs, DUT, clock generator and so forth. The testbench may consist of one or more test sequencers which are used to control the complete testbench architecture with any number of VVCs, although for a better testbench overview we recommend having a single central test sequencer only - for most testbenches.
Figure 1 Testbench example using the VVC framework A more detailed description on the VVC Framework and the command mechanism can be found in the VVC Framework Manual. Testbench SetupThe following mechanisms are required for running the VVC Framework: LibrariesIn order to use the VVC framework the following libraries need to be included: library uvvm_util; context uvvm_util.uvvm_util_context; library uvvm_vvc_framework; use uvvm_vvc_framework.ti_vvc_framework_support_pkg.all; Context filesThe context files are created to simplify the inclusion of necessary libraries used in UVVM.
The usage of these context files are shown below: library bitvis_vip_<name>; context bitvis_vip_<name>.vvc_context; library uvvm_util; context uvvm_util.uvvm_util_context; library uvvm_context; context uvvm_context.uvvm_support_context; library uvvm_context; context uvvm_context.uvvm_all_context; UVVM EngineThis entity contains a process that will initialize the UVVM environment, and must be instantiated in the testbench harness, or alternatively in the top-level testbench. -- Example: i_ti_uvvm_engine : entity uvvm_vvc_framework.ti_uvvm_engine; Important If the await_uvvm_initialization()This procedure is a blocking procedure that must be called from the testbench sequencer, prior to any VVC calls, to ensure that
the UVVM engine has been initialized and is ready. This procedure will check the shared_uvvm_state on each delta cycle until the
UVVM engine has been initialized. Note that this method is depending on the -- Example: await_uvvm_initialization(VOID); Important Not using the await_uvvm_completion()This procedure waits for all the VVCs to be inactive with no pending commands to be executed, and for all the enabled scoreboards to be empty, i.e. all expected values checked. It is therefore meant to be used at the end of the test sequencer. If any VVC is still active and/or an enabled scoreboard still has expected values to be checked when the timeout occurs, an alert will be generated. Otherwise, a successful completion message and the optional reports will be printed in the log. The printing destination can be log and/or console and is defined by the shared variable await_uvvm_completion(timeout, [alert_level, [sb_poll_time, [print_alert_counters, [print_sbs, [print_vvcs, [scope, [msg_id_panel]]]]]]])
-- Example: Wait for all transactions to finish await_uvvm_completion(1 ms); -- Example: Wait for all transactions to finish and report the alert counters, VVCs and scoreboards await_uvvm_completion(1 ms, TB_WARNING, 1 us, REPORT_ALERT_COUNTERS_FINAL, REPORT_SCOREBOARDS, REPORT_VVCS, C_SCOPE); Note
Hint If there is only need to check for VVCs to be inactive with no pending commands to be executed, one can also use the await_completion() procedure: -- Example: Wait for all VVCs to finish await_completion(ALL_VVCS, 1 ms, "Wait for all the VVCs to finish", C_SCOPE); If there are no VVCs in the testbench and only want to check for scoreboards to be empty, one can also use the await_sb_completion() procedure: -- Example: Wait for all Scoreboards to be empty await_sb_completion(1 ms, TB_WARNING, 1 us, NO_REPORT, REPORT_SCOREBOARDS, C_SCOPE); Common VVC Methods
await_completion()Tells the VVC to await the completion of either all pending commands or a specified command index. A message will be logged before and at the end of the wait. The procedure will report an alert if not all commands have completed within the specified timeout. The severity of this alert will be TB_ERROR. It is also possible to broadcast by setting vvc_select to ALL_VVCS (t_vvc_select) or to multicast using ALL_CHANNELS/ALL_INSTANCES (multicast.). To await the completion of one out of several VVCs in a group use the overload with the vvc_list. The vvc_list of type t_prot_vvc_list (protected type) is a local variable that needs to be declared in the sequencer. This overload will block the sequencer while waiting, but not the VVCs, so they can continue to receive commands from other sequencers. Important
await_completion(vvc_target, vvc_instance_idx, [vvc_channel], [wanted_idx], timeout, [msg, [scope]]) await_completion(vvc_select, vvc_list, [wanted_idx], timeout, [list_action, [msg, [scope]]]) await_completion(vvc_list, timeout, [list_action, [msg, [scope]]]) -- same as ALL_OF await_completion(vvc_select, timeout, [msg, [scope]]) -- use with ALL_VVCS (similar to BROADCAST)
-- Example, wait for any VVC to finish (ANY_OF): variable my_vvc_list : t_prot_vvc_list; ... add_to_vvc_list(SBI_VVCT, 1, my_vvc_list); add_to_vvc_list(UART_VVCT, ALL_INSTANCES, ALL_CHANNELS, my_vvc_list); await_completion(ANY_OF, my_vvc_list, 1 ms, KEEP_LIST, "Wait for any VVC in the list to finish", C_SCOPE); -- keep v_vvc_list entries for later -- Example, wait for all VVCs to finish (ALL_OF): variable my_vvc_list : t_prot_vvc_list; ... add_to_vvc_list(SBI_VVCT, 1, my_vvc_list); add_to_vvc_list(UART_VVCT, ALL_INSTANCES, ALL_CHANNELS, my_vvc_list); await_completion(ALL_OF, my_vvc_list, 1 ms, CLEAR_LIST, "Wait for any VVC in the list to finish", C_SCOPE); -- can be used without ALL_OF, clear v_vvc_list entries -- Example, wait for a specific VVC to finish: await_completion(SBI_VVCT, 1, 1 ms, "Waiting for SBI to finish.", C_SCOPE); await_completion(UART_VVCT, 1, TX, 1 ms, "Waiting for UART RX to finish.", C_SCOPE); await_completion(I2C_VVCT, ALL_INSTANCES, 1 ms, "Waiting for all I2C VVCs to finish.", C_SCOPE); -- Example, wait for a specific VVC command index to finish: await_completion(SBI_VVCT, 1, v_cmd_idx, 1 ms, "Waiting for SBI cmd " & to_string(v_cmd_idx) & " to finish.", C_SCOPE); -- Example, broadcast to all VVCs (ALL_VVCS): await_completion(ALL_VVCS, 1 ms, "Wait for all the VVCs to finish", C_SCOPE); add_to_vvc_list()Adds the VVC to a t_prot_vvc_list. The protected VVC list can be used with add_to_vvc_list(vvc_target, vvc_instance_idx, [vvc_channel], vvc_list)
-- Examples: variable my_vvc_list : t_prot_vvc_list; ... add_to_vvc_list(SBI_VVCT, 1, my_vvc_list); add_to_vvc_list(UART_VVCT, 1, ALL_CHANNELS, my_vvc_list); await_completion(ALL_OF, my_vvc_list, 1 ms, KEEP_LIST, "Wait for any VVC in the list to finish", C_SCOPE); v_vvc_list.clear_list(VOID); -- clear all VVC entries from list await_any_completion()Replaced by await_any_completion(vvc_target, vvc_instance_idx, [vvc_channel], [wanted_idx], lastness, [timeout, [msg, [awaiting_completion_idx, [scope]]]]) Warning This procedure is deprecated and will be removed in v3. For details and examples for using this call see UVVM release v2020.05.12 or any earlier releases. enable_log_msg()Instructs the VVC to enable a given log ID. This call will be forwarded to the UVVM Utility Library enable_log_msg() function. It is also possible to broadcast and multicast. enable_log_msg(vvc_target, vvc_instance_idx, [vvc_channel], msg_id, [msg, [quietness, [scope]]]) enable_log_msg(VVC_BROADCAST, msg_id, [msg, [quietness, [scope]]])
-- Examples: enable_log_msg(SBI_VVCT, 1, ID_LOG_BFM, "Enabling SBI BFM logging"); enable_log_msg(UART_VVCT, 1, TX, ID_LOG_BFM, "Enabling UART TX BFM logging", NON_QUIET, C_SCOPE); -- Broadcast: enable_log_msg(VVC_BROADCAST, ID_LOG_BFM, "Enabling BFM logging for all VVCs", NON_QUIET, C_SCOPE); disable_log_msg()Instructs the VVC to disable a given log ID. This call will be forwarded to the UVVM Utility Library disable_log_msg() function. It is also possible to broadcast and multicast. disable_log_msg(vvc_target, vvc_instance_idx, [vvc_channel], msg_id, [msg, [quietness, [scope]]]) disable_log_msg(VVC_BROADCAST, msg_id, [msg, [quietness, [scope]]])
-- Examples: disable_log_msg(SBI_VVCT, 1, ID_LOG_BFM, "Disabling SBI BFM logging"); disable_log_msg(UART_VVCT, 1, TX, ID_LOG_BFM, "Disabling UART TX BFM logging", NON_QUIET, C_SCOPE); -- Broadcast: disable_log_msg(VVC_BROADCAST, ALL_MESSAGES, "Disables all messages in all VVCs", NON_QUIET, C_SCOPE); flush_command_queue()Flushes the VVC command queue for the specified VVC target/channel. The procedure will log information with log ID ID_IMMEDIATE_CMD. It is also possible to broadcast and multicast. flush_command_queue(vvc_target, vvc_instance_idx, [vvc_channel], [msg, [scope]]) flush_command_queue(VVC_BROADCAST, [msg, [scope]])
-- Examples: flush_command_queue(SBI_VVCT, 1, "Flushing command queue", C_SCOPE); -- Broadcast: flush_command_queue(VVC_BROADCAST, "Flushing command queues", C_SCOPE); fetch_result()Fetches a stored result using the command index. A result is stored when using e.g. the read or receive commands in a VVC. The fetched result is available on the result output. The Boolean output fetch_is_accepted is used to indicate if the fetch was successful or not. A fetch can fail if e.g. the wanted_idx did not have a result to store, or the wanted_idx read has not yet been executed. Omitting the fetch_is_accepted parameter causes the parameters to be checked automatically in the procedure. On successful fetch, a message with log ID ID_UVVM_CMD_RESULT is logged. fetch_result(vvc_target, vvc_instance_idx, [vvc_channel], wanted_idx, result, [fetch_is_accepted], [msg, [alert_level, [scope]]])
-- Examples: fetch_result(SBI_VVCT,1, v_cmd_idx, v_data, v_is_ok, "Fetching read-result", C_SCOPE); -- Full example: sbi_read(SBI_VVCT, 1, C_ADDR_FIFO_GET, "Read from FIFO"); v_cmd_idx := get_last_received_cmd_idx(SBI_VVCT,1); -- Retrieve the command index await_completion(SBI_VVCT, 1, v_cmd_idx, 100 ns, "Wait for sbi_read to finish"); fetch_result(SBI_VVCT, 1, v_cmd_idx, v_data, v_is_ok, "Fetching read-result"); check_value(v_is_ok, ERROR, "Readback OK via fetch_result()"); insert_delay()Inserts a delay of delay clock cycles or delay seconds in the VVC. It is also possible to broadcast and multicast. insert_delay(vvc_target, vvc_instance_idx, [vvc_channel], delay, [msg, [scope]]) insert_delay(VVC_BROADCAST, delay, [msg, [scope]])
-- Examples: insert_delay(SBI_VVCT,1, 50 ns, "50 ns delay", C_SCOPE); insert_delay(SBI_VVCT,1, 100, "100T delay", C_SCOPE); -- Broadcast: insert_delay(VVC_BROADCAST, 50 ns, "Insert 50 ns delay to all VVCs", C_SCOPE); terminate_current_command()Terminates the current command in the VVC, if the currently running BFM command supports the terminate signal. It is also possible to broadcast and multicast. terminate_current_command(vvc_target, vvc_instance_idx, [vvc_channel], [msg, [scope]]) terminate_current_command(VVC_BROADCAST, [msg, [scope]])
-- Examples: terminate_current_command(SBI_VVCT, 1, "Terminating current command", C_SCOPE); -- Broadcast: terminate_current_command(VVC_BROADCAST, "Terminating current command in all VVCs", C_SCOPE); terminate_all_commands()Terminates the current command in the VVC, if the currently running BFM command supports the terminate signal. The procedure also flushes the VVC command queue, removing all pending commands. It is also possible to broadcast and multicast. terminate_all_commands(vvc_target, vvc_instance_idx, [vvc_channel], [msg, [scope]]) terminate_all_commands(VVC_BROADCAST, [msg, [scope]])
-- Examples: terminate_all_commands(SBI_VVCT, 1, "Terminating all commands", C_SCOPE); -- Broadcast: terminate_all_commands(VVC_BROADCAST, "Terminating all commands in all VVCs", C_SCOPE); get_last_received_cmd_idx()Gets the command index of the last command received by the VVC interpreter. Necessary for getting the command index of a read for fetch_result. get_last_received_cmd_idx(vvc_target, vvc_instance_idx, [vvc_channel, [scope]])
-- Examples: v_cmd_idx := get_last_received_cmd_idx(SBI_VVCT, 1, C_SCOPE); Broadcasting and MulticastingCommands in UVVM can be distributed to all instances of a VVC or to all VVCs using dedicated parameters. VVC_BROADCASTThe VVC_BROADCAST command parameter can be used when a command is to target all VVCs within the test environment, reducing the number of command instructions needed in the testbench. -- Examples: enable_log_msg(VVC_BROADCAST, ALL_MESSAGES); -- enable logging for all VVCs await_completion(VVC_BROADCAST, 10 us); -- wait for all VVCs to complete ALL_INSTANCESThe ALL_INSTANCES command parameter can be used when a command is targeting all instances of a VVC within the test environment, reducing the number of command instructions needed in the testbench. -- Examples: enable_log_msg(SBI_VVCT, ALL_INSTANCES, ALL_MESSAGES); -- enable logging for all instances of SBI_VVCT await_completion(SBI_VVCT, ALL_INSTANCES, 100 ns); -- wait for all instances of SBI_VVCT to complete ALL_CHANNELSThe ALL_CHANNELS command parameter can be used when a command is targeting all channels of a VVC within the test environment, reducing the number of command instructions needed in the testbench. -- Examples: enable_log_msg(UART_VVCT, 1, ALL_CHANNELS, ALL_MESSAGES); -- enable logging for all channels of UART_VVCT instance 1 await_completion(UART_VVCT, ALL_INSTANCES, ALL_CHANNELS, 100 ns); -- wait for all instances and channels of UART_VVCT to complete C_VVCT_ALL_INSTANCESSee description above. C_VVCT_ALL_INSTANCES = ALL_INSTANCES. Warning This command parameter might be removed in a future release and we encourage the use of ALL_INSTANCES. VVC Mechanisms and FeaturesThis section explains some of the mechanisms necessary for running the VVC Framework and the VVC features which are included in all or certain VVCs. VVC typesSome VVC-related types will need to be hierarchically declared, based on their package name, in order to avoid ambiguity among different VVCs. If only a single VVC is needed: --Example: variable v_result : t_vvc_result; If several VVCs are needed: --Example: variable v_spi_result : bitvis_vip_spi.vvc_cmd_pkg.t_vvc_result; variable v_axi_result : bitvis_vip_axi.vvc_cmd_pkg.t_vvc_result; t_vvc_resultThe common type t_vvc_result is always defined with the max length of fetched data that the VVC supports (see the definition of t_vvc_result in its corresponding vvc_cmd_pkg.vhd). Therefore it is recommended to define the range of the desired data output after the fetch_result method has been completed. --Example: variable v_data : t_vvc_result; variable v_data_out : std_logic_vector(7 downto 0); And then: fetch_result(SPI_VVCT, 1, v_cmd_idx, v_data, "Fetching result of SPI receive operation"); v_data_out := v_data(7 downto 0); VVC Shared Variables and Global SignalsVVC shared variables and global signals are defined in the various VVC packages. Each VVC instance and channel can be configured and useful information can be accessed from the testbench via dedicated shared variables. Note shared_uvvm_status.info_on_finishing_await_any_completion is deprecated and will be removed in v3. For details and examples for using this shared variable see UVVM release v2020.05.12 or any earlier releases. shared_<vvc_name>_vvc_configFrom the VVC configuration shared variable, one is given the ability to tailor each VVC to one’s needs, in addition to access the BFM configuration record via the bfm_config identifier. In addition to BFM configuration possibility, the configuration settings consist of command and result queue settings, BFM access separation delay and a VVC dedicated message ID panel. Note that some BFMs require user configuration, e.g. the bit_time setting in serial interface BFMs. shared_sbi_vvc_config(1).inter_bfm_delay.delay_type := TIME_START2START; shared_uart_vvc_config(RX,1).bfm_config.bit_time := C_BIT_TIME; shared_<vvc_name>_vvc_statusThe VVC status shared variable provides access to the command status parameters for each of the VVCs, such as the current and previous command index, and the number of pending commands in the VVCs command queue. This provides a helpful tool, e.g. when synchronizing VVCs in the test sequencer using the await_completion() method. v_num_pending_cmds := shared_sbi_vvc_status(1).pending_cmd_cnt; v_current_cmd_idx := shared_uart_vvc_status(TX,2).current_cmd_idx; v_previous_cmd_idx := shared_uart_vvc_status(TX,2).previous_cmd_idx; shared_<vvc_name>_transaction_infoNote This shared variable is deprecated and will be removed in v3. It has been replaced for global_<vvc_name>_vvc_transaction_triggerGlobal trigger signal for when a VVC has updated its shared variable with VVC transaction info. See Distribution of Transaction Info - From VVCs and/or Monitors for more details. shared_<vvc_name>_vvc_transaction_infoShared variable providing access to Transaction Info VVC instances. See Distribution of Transaction Info - From VVCs and/or Monitors for more details. Available information is dependent on VVC type and typical information is: operation : t_operation; -- default NO_OPERATION data : std_logic_vector(C_VVC_CMD_DATA_MAX_LENGTH-1 downto 0); -- default 0x0 vvc_meta : t_vvc_meta; -- default C_VVC_META_DEFAFULT transaction_status : t_transaction_status; -- default INACTIVE Note This shared variable is replacing the VVC Local SequencersUVVM testbenches may have one or more central sequencers – also known as test sequencers or test drivers. A single test sequencer is recommended in order to reduce complexity – as synchronization between multiple parallel test sequencer could be really complex. UVVM does however also provide support for so called local sequencers. These sequencers will typically run inside the VVCs executor process. The executor will typically run a single transaction via a BFM procedure towards the DUT interface, like an sbi_write() or uart_expect() procedure. For more advanced VVCs it would however make sense to send even higher level commands to a VVC, like requesting it to transmit N random bytes, or setting up a peripheral by writing to multiple configuration registers. In these cases, a single command to the VVC will trigger a complete sequence of accesses towards the DUT. The code inside the VVC executors handling these sequences are called local sequencers as they are local to the VVC and thus also improves re-use. These sequences of transactions may also be defined as Compound Transactions (see Transaction definitions). An example of a local sequencer is the randomization sequences in the UART VVC, and poll_until in the SBI VVC. Local sequencer requirementsThe following requirements should be followed when making local sequencers (basically any VVC command resulting in more than one base transaction):
Controlling Property CheckersA major VVC advantage is that lots of very useful additional functionality may be added inside the VVC entity, meaning that all the verification support for a given interface can be encapsulated inside a single VHDL entity. A major advantage of UVVM is that adding additional functionality and controlling it from the test sequencers is really simple. One very useful additional functionality is property checkers, and some typical examples of this could be to check the minimum allowed bit period, the minimum inter-packet gap, back-to-back restrictions, etc., or in general to check a given requirement continuously - especially when this is easier to do outside the BFM - for instance in a dedicated checker process. A dedicated checker process would typically just wait for a trigger condition on the interface (like a UART data bit changing its level), then wait again for a next trigger (the next data bit), and then check that the time between the two changes is not less than the minimum allowed bit period. This check could then be repeated forever. It is however recommended that the check could be turned on and off for more flexibility. Property check configurationIn UVVM, turning checkers on and off is controlled by the VVC configuration (see shared_<vvc_name>_vvc_config), and often additional control of the checker behavior is also required. Thus, it is recommended to include the checker control for each individual check in a dedicated sub-record. An example on this (for the UART VVC) is shown below. See UART VVC for implementation. .bit_rate_checker -- Sub-record containing all control of the property checker behavior .enable boolean -- Enables or disables the complete bit rate checker .min_period time .alert_level t_alert_level For this example, the bit rate checker inside the UART_VVC RX will trigger on changes on the DUT TX and execute the check if enable is TRUE. Setting up the configurationThe bit rate checker configuration may be changed directly from the sequencer via the shared variable VVC configuration. Scope of Verbosity ControlMessage IDs are used for verbosity control in many of the procedures and functions in UVVM, as well as log messages and checks
in VVCs, BFMs and Scoreboards. The UVVM procedures and functions use a default global message ID panel called
shared_msg_id_panel which has a default value of C_MSG_ID_PANEL_DEFAULT configured in adaptations_pkg.Note that VVCs and Scoreboards come with dedicated message ID panels and are not affected by the global message ID panel, but
accessed by addressing the targeting VVC or Scoreboard and, if applicable, instance number or with a broadcast. The default
value for these message ID panels is set by C_VVC_MSG_ID_PANEL_DEFAULT and C_SB_MSG_ID_PANEL_DEFAULT in adaptations_pkg.
Also note that when a VVC is executing commands triggered by an HVVC (Hierarchical-VVC), e.g. SBI write due to Ethernet transmit,
the VVC will use the HVVC’s message ID panel instead. See Hierarchical VVCs for an example of the HVVC
structure.
-- Global message ID panel. Does not apply to VVCs or Scoreboards, as they have their own local message ID panel disable_log_msg(ALL_MESSAGES); enable_log_msg(ID_SEQUENCER); -- VVC message ID panel disable_log_msg(VVC_BROADCAST, ALL_MESSAGES); -- broadcast to all VVCs and instances enable_log_msg(I2C_VVCT, C_VVC_INSTANCE_1, ID_BFM_WAIT); -- I2C VVC instance 1 enable_log_msg(I2C_VVTC, C_VVC_INSTANCE_2, ID_BFM_WAIT); -- I2C VVC instance 2 -- Scoreboard message ID panel shared variable sb_under_test : record_sb_pkg.t_generic_sb; ... sb_under_test.disable_log_msg(ALL_INSTANCES, ID_CTRL); -- broadcast to all SB instances sb_under_test.enable_log_msg(C_SB_INSTANCE_1, ID_DATA); -- SB instance 1 The predefined message IDs are listed in Message IDs. Activity WatchdogThe VVC Framework has an activity watchdog mechanism which all Bitvis VVCs support. All VVCs can be automatically registered in a centralized VVC activity register at start-up and will, during simulation, update the VVC activity register with their current activity status, i.e. ACTIVE or INACTIVE, which again is monitored by the activity watchdog. A timeout counter in the activity watchdog will start after the last update has occurred in the VVC activity register, and the timeout counter is reset on any VVC activity. An alert will be raised if none of the VVCs have an activity prior to the timeout counter reaching the specified timeout value. Note that the activity watchdog will continue to monitor VVC activity, even after a timeout, until alert stop limit is reached. The activity watchdog has to be included as a concurrent procedure parallel to the testbench sequencer or in the test harness in order to be activated. Note that the activity watchdog will raise a TB_WARNING if the number of expected VVCs does not match the number of registered VVCs in the VVC activity register, and that leaf VVCs (e.g. channels such as UART RX and TX) are counted individually. This checking can be disabled by setting the number of expected VVCs to 0. Also note that the total number of VVCs registered in the VVC activity register cannot exceed the C_MAX_TB_VVC_NUM count, default set to 20 in the adaptations_pkg, and this will result in a TB_ERROR raised by the VVC activity register. Note that some VVCs should not be monitored by the activity watchdog. This currently applies to the clock generator VVC, as this VVC may continue to be active even after all other testbench activity has stopped. This VVC will have to be included in the number of expected VVCs registered in the VVC activity register but will not have any effect on the activity watchdog timeout counter.
-- Example: p_activity_watchdog: activity_watchdog(num_exp_vvc => 3, timeout => C_ACTIVITY_WATCHDOG_TIMEOUT); Built-in randomizationUVVM provides functions and procedures for simple generation of random numbers (integer, real, time, std_logic and std_logic_vector), described in Basic Randomization. It also provides a more complete randomization package using protected types, which is described in Enhanced Randomization. And a more advanced randomization without replacement, described in Optimized Randomization. Note Only some VVCs currently include built-in randomization (e.g. UART TX VVC and SBI VVC.) The principles shown for these VVCs may be applied directly also for a user defined VIP. UVVM VIP randomization principlesRandomization may of course be applied with no limitations in a UVVM based testbench. For UVVM VIP however, we recommend the same general approach as for error injection randomization:
Data randomization in BFMsThere is no data randomization inside a normal BFM, for the reason given above. Data randomization in VVCsA VVC may be commanded to generate constrained random data, where data in this sense could also be addresses, lengths, etc. Typically such commands would allow flexibility for the number of accesses and other important aspects - like scoreboards, common buffers, files, etc. A few randomization profiles have been predefined both as typical use cases and as examples for future extensions, when needed. The profile names are defined in the type t_randomisation, which is declared in the adaptations_pkg to allow users to add more profiles.
Note that the randomization seeds are initialized with a unique string assigned to each VVC. These seeds are automatically updated when random data is generated. Managing randomization seeds in BFMsFlow Control signals (e.g. valid and ready) can be configured to be randomly de-asserted in some BFMs (e.g. AXI-Stream and Avalon-ST). The randomization parameters in the BFM configuration determine the low duration and the probability of signal de-assertion. The random() methods described in Basic Randomization are used to generate random values for these parameters. To ensure that the tests are repeatable and produce consistent results, the randomization seeds must be controlled. A standard dictionary-like linked list is implemented for this purpose. The seeds are managed using the protected type t_seeds, declared in protected_types_pkg.vhd. This type consists of the t_seeds_item record type, which holds the seeds, and an access type that points to a dynamically allocated t_seeds_item. The seeds are stored in a record using a unique string (scope and instance_name) assigned to each BFM procedure as keys. To facilitate seed management, two subprograms are declared in the t_seeds protected type:
A global shared variable shared variable shared_rand_seeds_register : t_seeds; The randomization steps used to control the seeds in BFMs are as follow:
The handling of randomization seeds is hidden from the user and performed automatically. Therefore, the user does not require to change or
modify testbenches to control the randomization seeds. If a new BFM requires this functionality, it only needs to invoke the
-- Search the randomization seeds register with the scope and instance_name attribute as keys. The updated seeds are stored in v_seeds. shared_rand_seeds_register.update_and_get_seeds(scope, v_seeds'instance_name, v_seeds); random(1, config.valid_low_max_random_duration, v_seeds(0), v_seeds(1), v_valid_low_duration); Distribution of Transaction Info - From VVCs and/or MonitorsUVVM supports sharing transaction information in a controlled manner within the complete testbench environment. This allows VVCs and Monitors to provide transaction info to any other part of your testbench – using a predefined structured mechanism. This makes it even easier to make good VHDL testbenches. Transaction information may be used in many different ways, but the main purpose is to share information inside the testbench of activity or accesses on a given DUT interface. Such information could typically be provided from a dedicated interface Monitor, but making such a dedicated Monitor is sometimes quite time consuming and often not really needed. For that reason, UVVM provides a mechanism for getting the transaction information directly from the VVC. PurposeBy enabling the distribution of transaction info, models or any other parts of the testbench can see exactly what accesses have been made on the various interfaces of the DUT, so that the expected DUT behavior and outputs may be checked. Let us illustrate this with a really simple testbench scenario to verify a UART peripheral with an AXI-lite register/CPU interface on one side and the UART RX and TX ports on the other side. The test sequencer may command the AXI-lite BFM or VVC to write a data byte into the UART TX register, and then it must be checked that the data byte is transmitted out on the DUT TX output some time later.
However, for the two latter approaches the model needs information about exactly what happened (the transaction) on the various DUT interfaces, so that it can generate the correct expected data. For the model it doesn’t matter if the transaction info comes from a Monitor or from a VVC, as long as the information is correct. The model could of course look at the interfaces and analyze the actual transactions, but distributing this task to the VVC or Monitor makes the testbench far more structured and significantly improves overview, maintenance, extensibility and reuse – at least for anything above medium simple verification challenges. Another purpose of providing transaction information is for progress viewing and debugging – typically via the wave view or simulation transcripts.
Transaction definitionsBy transactions we normally talk about a complete end to end transfer of data across an interface. This could be anything from a simple write, read or transfer of a single word - to a complete packet in a packet-oriented protocol like Ethernet. The word transaction is however also used for both sub-sets and super-sets of this – depending on the protocol and even on how we want to control our system or testbench. In order to communicate properly and to assure that transactions are properly understood, the following terms are defined:
Transaction informationInformation about the above transactions is typically provided to a model in the test harness. Depending on whether the transaction info is provided from the VVC or Monitor, different types of information will be available. Common for both is that they always provide info about the operation (read, write, transmit, etc.) and often also any other protocol specific info. For a UART this could be data and parity, for an SBI it could be address and data, and for Ethernet, the packet fields. This minimum is normally what the Monitor can provide from just analyzing the interface, and this is also normally enough for a model to generate expected DUT outputs. The VVC on the other hand, can provide more info, which could be useful for instance for progress viewing and debugging. The transaction information is organized as a transaction record with some predefined fields as shown below. Table 1 shows the general transaction record, whereas table 2 shows a concrete example for the SBI. Note that for a given interface/protocol, the VVC and the Monitor will use the same interface dedicated transaction record type - with some fields potentially unused.
Other interfaces will of course have different protocol dedicated fields, or even a complete protocol dedicated sub-record (e.g. for Ethernet packet fields). Transaction Info transferIn order to reduce the number of signals from a VVC or Monitor, all possible simultaneous transactions (and their transaction records) are collected into a single transaction group record. For an SBI interface, this will consist of a BT record and potentially a CT record. Whereas for an Avalon, it will in addition also consist of two ST records, because for instance a read request may be active at the same time as a read response. (And the sub-transactions are part of a base transaction and may also be part of a CT). Table 3 shows the maximum transaction group record for an SBI, whereas Table 4 shows the maximum transaction group record for an Avalon MM. The bold CT is optional for both, and thus depends on whether CTs have been defined in the VVC. Multiple parallel STs may be written to the transaction group record simultaneously - as these are handled by different “threads” (concurrent statements like a process). A Monitor cannot know about CTs, and thus a Monitor will never fill in that sub-record. A Monitor for a split transaction protocol (i.e. with multiple STs) may or may not provide BT info. If it does, this should normally be implemented in a higher level “wrapper”. Note
Hint
Transaction Info record signalsThe Transaction Info record is provided out of the VVC and Monitor using sets of a global signal and a shared variable. These and all Transaction Info related VHDL types are defined in transaction_pkg.vhd, located in the VIP src folder (except for the t_transaction_status type, which is defined in types_pkg.vhd).
Note Transaction Info signal and shared variableA VVC or Monitor will trigger the global trigger signals listed in Transaction Info record signals when information of a new transaction info is made available. For a VVC, the transaction info can be available prior to the corresponding bus access, i.e. before calling the BFM method, or at the end of the access, i.e. when the BFM method has finished. The global trigger signal will be pulsed in both cases for a delta cycle. The VVC will set the transaction info back to default values immediately after the second trigger, but then without pulsing the global trigger signal. For a Monitor, the transaction info will be made available immediately after a bus access is completed and then the global trigger signal will be pulsed for a delta cycle. The transaction info is valid when the global trigger signal is pulsed and it is set back to default values after a period of transaction_display_time, set in the Monitor configuration record, or when a new transaction is started. Examples of Transaction Info UsageAll important information regarding a transfer is available in the transaction info and accessible in the test environment, and depending on one’s needs there are some recommended approaches for how to utilize the transaction info:
MechanismThe technique of using transaction info in the test environment, either in a VVC scoreboard support process or in a DUT Model, involves the following 3 steps:
A simple VVC Scoreboard Support process is presented in Figure 6, demonstrating how VVC scoreboard actions can be accomplished using transaction info and a stand-alone process when not performed by a VVC. The same approach is shown in Figure 7 with a simple DUT Model process, demonstrating how DUT modelling can be accomplished using transaction info and a stand-alone process. Note that Figure 6 uses aliasing to simplify and improve code readability, while Figure 7 uses full transaction info names. Figure 6 VVC Scoreboard Support – with aliasing
p_vvc_sb_support : process -- transaction info handles alias sbi_transaction_trigger : std_logic is global_sbi_vvc_transaction_trigger(C_SBI_VVC_1); alias sbi_transaction_info : bitvis_vip_sbi.transaction_pkg.t_base_transaction is shared_sbi_vvc_transaction_info(C_SBI_VVC_1).bt; alias uart_rx_transaction_trigger : std_logic is global_uart_vvc_transaction_trigger(RX, C_UART_VVC_1); alias uart_rx_info : bitvis_vip_uart.transaction_pkg.t_base_transaction is shared_uart_vvc_transaction_info(RX, C_UART_VVC_1).bt; -- helper variable variable v_sb_element : std_logic_vector(C_DATA_WIDTH-1 downto 0); begin while true loop: -- Wait for available transaction info wait until (sbi_transaction_trigger = '1') or (uart_rx_transaction_trigger = '1'); if sbi_transaction_trigger'event then if sbi_transaction_info.operation = READ and sbi_transaction_info.transaction_status = COMPLETED then v_sb_element := sbi_transaction_info.data(C_DATA_WIDTH-1 downto 0); sbi_vvc_sb.check_received(C_SBI_VVC_1, v_sb_element); end if; end if; if uart_rx_transaction_trigger'event then if uart_rx_info.operation = RECEIVE and uart_rx_info.transaction_status = COMPLETED then v_sb_element := uart_rx_info.data(C_DATA_WIDTH-1 downto 0); uart_vvc_sb.check_received(C_UART_VVC_1, v_sb_element); end if; end if; end loop; end process p_vvc_sb_support; Figure 6 demonstrates the setup of a VVC Scoreboard Support process that operates with the 3 steps listed in Transaction Info Mechanism. For simple scoreboard elements, such as std_logic_vector, these scoreboard approaches are already performed by the VVCs. Figure 7 DUT Model – no aliasing
p_dut_model : process begin while true loop: -- Wait for available transaction info wait until (global_sbi_vvc_transaction_trigger(C_SBI_VVC_1) = '1') or (global_uart_vvc_transaction_trigger(TX, C_UART_VVC_1) = '1'); if global_sbi_vvc_transaction_trigger(C_SBI_VVC_1)'event then if shared_sbi_vvc_transaction_info(C_SBI_VVC_1).bt.operation = WRITE and shared_sbi_vvc_transaction_info(C_SBI_VVC_1).bt.transaction_status = IN_PROGRESS then uart_vvc_sb.add_expected(shared_sbi_vvc_transaction_info(C_SBI_VVC_1).bt.data(C_DATA_WIDTH-1 downto 0)); end if; end if; if global_uart_vvc_transaction_trigger(TX, C_UART_VVC_1)'event then if shared_uart_vvc_transaction_info(TX, C_UART_VVC_1).bt.operation = TRANSMIT and shared_uart_vvc_transaction_info(TX, C_UART_VVC_1).bt.transaction_status = IN_PROGRESS then sbi_vvc_sb.add_expected(shared_uart_vvc_transaction(TX, C_UART_VVC_1).bt.data(C_DATA_WIDTH-1 downto 0)); end if; end if; end loop; end process p_dut_model; Figure 7 demonstrates the setup of a DUT Model process that operates with the 3 steps listed in Transaction Info Mechanism. For simple scoreboard elements, such as std_logic_vector, these scoreboard approaches are already performed by the VVCs. Complex ProtocolsFor scoreboards with complex protocols, e.g. AXI Stream and Avalon ST, the same approach as listed in Transaction Info Mechanism applies. The only difference is that the scoreboard element is of a more complex type, i.e. a record element. Figure 8 demonstrates a VVC scoreboard support approach using a complex record element. Figure 8 VVC Scoreboard Support – complex scoreboard element
-- define complex Avalon ST scoreboard type type t_avalon_st_element is record channel_value : std_logic_vector(C_CH_WIDTH-1 downto 0); data_array : t_slv_array(0 to C_ARRAY_LENGTH-1)(C_WORD_WIDTH-1 downto 0); end record t_avalon_st_element; -- create to_string() function for t_avalon_st_element function avalon_st_element_to_string( constant rec_element : t_avalon_st_element ) return string is begin return "channel value: " & to_string(rec_element.channel_value) & ", data: " & to_string(rec_element.data_array); end function avalon_st_element_to_string; -- define Avalon ST scoreboard package avalon_st_sb_pkg is new bitvis_vip_scoreboard.generic_sb_package generic map(t_element => t_avalon_st_element, element_match => "=", to_string_element => avalon_st_element_to_string); use avalon_st_sb_pkg.all; shared variable avalon_st_vvc_sb : avalon_st_sb_pkg.t_generic_sb; ... p_vvc_sb_support : process -- transaction info handles alias avalon_st_transaction_trigger : std_logic is global_avalon_st_vvc_transaction_trigger(C_AVALON_ST_VVC_1); alias avalon_st_transaction_info : bitvis_vip_avalon_st.transaction_pkg.t_base_transaction is shared_avalon_st_vvc_transaction_info(C_AVALON_ST_VVC_1).bt; -- helper variable variable v_sb_element : t_avalon_st_element; begin while true loop: -- Wait for available transaction info wait until avalon_st_transaction_trigger = '1'; if avalon_st_transaction_trigger'event then if avalon_st_transaction_info.operation = RECEIVE and avalon_st_transaction_info.transaction_status = COMPLETED then v_sb_element.channel_value := avalon_st_transaction_info.channel_value(C_CH_WIDTH-1 downto 0); v_sb_element.data_array := avalon_st_transaction_info.data_array(0 to C_ARRAY_LENGTH-1)(C_WORD_WIDTH-1 downto 0); avalon_st_vvc_sb.check_received(C_AVALON_ST_VVC_1, v_sb_element); end if; end if; end loop; end process p_vvc_sb_support; Figure 8 demonstrates the setup of a VVC Scoreboard Support process that operates with the 3 steps listed in Transaction Info Mechanism. For complex scoreboard elements, such as records, the scoreboard package declaration, defining the shared variable and scoreboard approaches have to be performed outside the VVC. Protocol Aware Error InjectionError injection into the DUT could be very useful in a testbench in order to test how the DUT handles interface errors when these errors are: a) to be detected and corrected, b) detected only, and c) not detected but may or may not affect the behavior. Protocol aware error injection is defined here as intelligent error injection, given knowledge about the interface and protocol, e.g. to inject a parity error in a protocol rather than just inverting or delaying a signal without predefined detailed support to do this at the right place. The latter is supported by a dedicated “brute force” error injection VIP ‘bitvis_vip_error_injection’ in UVVM. UVVM has a predefined methodology for handling protocol aware error injection in a structured way. Note Only some VVCs and BFMs currently support error injection. The principles shown for these VVCs and BFMs may be applied directly also for user defined VIP. UVVM error injection principlesError injection may be applied randomly, with no limitations. For UVVM however, we recommend the following approach:
Error injection in BFMsIn order to simplify the specification of which errors to inject, the complete error injection specification is given as a sub-record inside the BFM configuration. E.g. inside the UART BFM configuration the following sub-record is defined - with fields specifying the error injection details (details given in UART BFM).
In order to initiate error injection, the BFM config record must be modified and included in the BFM procedure call. Error injection in VVCsIn order to simplify the specification of which errors to inject, the complete error injection specification is given as a sub-record inside the VVC configuration (Note: not the BFM config). E.g. inside the UART VVC configuration the following sub-record is defined - with fields specifying the error injection details (Details given in UART VVC).
In order to initiate error injection, the VVC config record must be assigned the wanted values via the VVC configuration shared variable (see shared_<vvc_name>_vvc_config). Note The Error injection sub-record inside the VVC configuration will override that of the BFM configuration. Any compound or more advanced transactions may of course also request error injection directly or indirectly via the VVC command itself. Naming and type usageThe error injection sub-record will be VVC and BFM dedicated, and thus any names and types may be used, and even sub-records under ‘error_injection’ is required. The VVC and BFM error injection records may differ or be the same. The only requirement is that readability is prioritized. Values should be checked against legal ranges or values. Testbench Data RoutingTransaction Info is providing a mechanism for passively routing source data (data entered into the DUT) out of the VVCs to other parts of the testbench. This data routing is passive in the sense that the transaction data is just provided as a shared variable - for anyone to read. This is covered in Distribution of Transaction Info - From VVCs and/or Monitors. There is however also a need for routing data actively inside the testbench, where routing means fetching from or sending to predefined sources and destinations. To/from BufferUVVM has a global buffer that is divided into multiple smaller buffers that may be indexed and accessed from anywhere in the testbench. This functionality is described in UVVM Data FIFO. VVC commands requesting sourcing data from or sending data to these buffers use parameter TO_BUFFER or FROM_BUFFER, followed by the buffer index. To ScoreboardScoreboards may be used anywhere inside the testbench, but for UVVM the following is recommended:
VVC commands requesting sending data to the Scoreboard use parameter TO_SB. Data routing optionsThe profile names are defined in the type t_data_routing, which is defined in types_pkg.vhd
Unwanted Transaction DetectionThe UVVM VVCs support detection of unwanted or unexpected transactions from the DUT. This mechanism will give an alert if the DUT generates any unexpected bus activity that signals a transaction, e.g. asserting the valid signal. It assures that no data is output from the DUT when it is not expected, e.g. receive/read/check/expect VVC methods are not called. Once the VVCs are inactive, they start to monitor continuously on the DUT outputs. When unwanted transactions are detected, the VVCs issue an alert of severity. All VVC method packages contain a configuration in the t_vvc_config type for enabling unwanted transaction detection. The default value for this configuration is set to true in the adaptations_pkg, e.g. constant C_UNWANTED_TRANSACTION_CHECKING_DEFAULT : boolean := true; The unwanted transaction detection can be configured from the central testbench sequencer, where the severity of alert can be changed individually for each monitored signal, e.g. for GMII VVC: shared_gmii_vvc_config(RX, C_VVC_INDEX).unwanted_transaction_severity.rxd := WARNING; shared_gmii_vvc_config(RX, C_VVC_INDEX).unwanted_transaction_severity.rxdv := ERROR; If multiple slave VVCs with a common bus are connected to the same master DUT as seen in Figure 2, unwanted transaction detection will give alerts on the inactive slave VVCs. For instance, when the data is expected on I2C slave VVC 1, an alert will be initiated from I2C slave VVC 2 and 3.
Figure 2 A false unwanted transaction detection scenario when multiple slave VVCs are connected to the same master DUT In order to avoid getting any false alerts, the unwanted transaction must be disabled on the inactive VVCs as shown below example. Note that the unwanted transaction detection must be enabled again after the data transfer is complete. -- Example: -- Expect data on I2C slave VVC 1. shared_i2c_vvc_config(2).unwanted_transaction_checking_enabled := false; -- Disable unwanted transaction on slave VVC 2 shared_i2c_vvc_config(3).unwanted_transaction_checking_enabled := false; -- Disable unwanted transaction on slave VVC 3 sbi_write(SBI_VVCT, 0, C_ADDR_TX_DATA, x"55", "Transmit data"); i2c_slave_check(I2C_VVCT, 1, x"55", "Slave check data"); await_completion(I2C_VVCT, 1, 50 ms); shared_i2c_vvc_config(2).unwanted_transaction_checking_enabled := true; -- Enable unwanted transaction on slave VVC 2 shared_i2c_vvc_config(3).unwanted_transaction_checking_enabled := true; -- Enable unwanted transaction on slave VVC 3 -- Expect data on I2C slave VVC 2 shared_i2c_vvc_config(1).unwanted_transaction_checking_enabled := false; -- Disable unwanted transaction on slave VVC 1 shared_i2c_vvc_config(3).unwanted_transaction_checking_enabled := false; -- Disable unwanted transaction on slave VVC 3 sbi_write(SBI_VVCT, 0, C_ADDR_TX_DATA, x"55", "Transmit data"); i2c_slave_check(I2C_VVCT, 2, x"55", "Slave check data"); await_completion(I2C_VVCT, 2, 50 ms); shared_i2c_vvc_config(1).unwanted_transaction_checking_enabled := true; -- Enable unwanted transaction on slave VVC 1 shared_i2c_vvc_config(3).unwanted_transaction_checking_enabled := true; -- Enable unwanted transaction on slave VVC 3 -- Expect data on I2C slave VVC 3 shared_i2c_vvc_config(1).unwanted_transaction_checking_enabled := false; -- Disable unwanted transaction on slave VVC 1 shared_i2c_vvc_config(2).unwanted_transaction_checking_enabled := false; -- Disable unwanted transaction on slave VVC 2 sbi_write(SBI_VVCT, 0, C_ADDR_TX_DATA, x"55", "Transmit data"); i2c_slave_check(I2C_VVCT, 3, x"55", "Slave check data"); await_completion(I2C_VVCT, 3, 50 ms); shared_i2c_vvc_config(1).unwanted_transaction_checking_enabled := true; -- Enable unwanted transaction on slave VVC 1 shared_i2c_vvc_config(2).unwanted_transaction_checking_enabled := true; -- Enable unwanted transaction on slave VVC 2 When the reset signal is set, signal transitions may occur from the uninitialized value ‘U’. Additionally, using pull-up or pull-down resistors in the design may cause signal transitions from the weak 1 state ‘H’ to the logic high ‘1’ or from the weak 0 state ‘L’ to the logic low ‘0’, and vice versa. It is also possible for signal transitions to occur from the unknown state ‘X’ to the logic low ‘0’ or logic high ‘1’ when simulating Verilog components during the initialization. These are all intended behaviors that should not be monitored by the unwanted transaction detection. The signal transitions that are excluded from unwanted transaction detection are summarized below.
For a VVC specific description of this feature, see the Unwanted Transaction Detection section in each VVC’s documentation. Note
Compile ScriptsIn the script folder in the root directory the compile_all.do compiles all UVVM components. This script may be called with one to three input arguments:
Example: do uvvm/script/compile_all.do uvvm/script
There are also compile scripts for all UVVM components located in the script folder of each UVVM component. These scripts can be called with two input arguments:
Example: do uvvm/uvvm_vvc_framework/script/compile_src.do uvvm/uvvm_vvc_framework
MonitorsMonitors could be great to check the interface accesses to a DUT - to report the transaction to the testbench - with all relevant info like operation (write, read, transmit, …), data, address, etc. This information may be critical in order to understand the operation of the DUT and its expected outputs. A monitor is not a protocol checker, but may of course check various properties of an interface/protocol. A typical Monitor will however only provide the relevant basic information and leave more advance interpretation to other parts of a testbench. For simple protocols like the UART, UVVM also includes basic error checking in the Monitor - as this happens at a very low level. For more advanced protocols it would make sense to just pass on the low level info to a higher level checker. The reason for making a dedicated monitor rather than leaving that to the testbench model is to achieve a better testbench structure and more efficient reuse. It should however be mentioned that implementing Transaction Info (see Distribution of Transaction Info - From VVCs and/or Monitors) inside a VVC significantly reduces the need for a dedicated monitor, as the VVC will then be able to pass the complete transaction information on to, for instance, a model inside the Testbench. Transfer of Monitor information to the testbenchThe mechanism for passing the monitor deduced transaction out of the monitor is almost exactly the same as for passing transaction info out of a VVC - as described in Distribution of Transaction Info - From VVCs and/or Monitors. The only difference is that the monitor can only provide parts of what the VVC can provide.
As the monitor does not know what to expect at the beginning of a transaction the following field limitations apply:
An example of a complete monitor is shown in the UART VIP directory. Transaction info transfer signalsThe Transaction info provided out of a Monitor uses a set of a global signal and a shared variable. These and all related VHDL types are defined in transaction_pkg.vhd.
See Transaction Info record signals Table 5 for more details. Hierarchical VVCsMany protocols and applications consist of several abstraction levels, e.g. physical layer, link layer, transaction layer, etc. When writing a test case for a higher level you most likely want to ignore the underlying levels and only deal with the scope of the relevant level. The test case will be less complex and easier to both write and read. A hierarchical VVC (HVVC) is a VVC of a higher protocol level than the physical layer, i.e. it has no physical connections. The test case only communicates with the HVVC which communicate with the lower level. Data is propagated upwards and downwards between the HVVC and DUT through a standard VVC connected to the DUT. The HVVC-to-VVC Bridge is the connection between a hierarchical VVC (HVVC) and the VVC at a lower protocol level, in this context referred to only as the VVC. Communications between the HVVC and VVC is handled by the HVVC-to-VVC Bridge. Data is transferred between the HVVC and HVVC-to-VVC Bridge on a common interface and converted in the HVVC-to-VVC Bridge to/from the specific interface of the VVC used. An example of this concept used on Ethernet is seen in Figure 9.
Figure 9 Example of HVVC-to-VVC Bridge implemented in an Ethernet HVVC HVVC usageTo simulate an HVVC you only need to do the following:
i1_ethernet_vvc : entity bitvis_vip_ethernet.ethernet_vvc generic map( GC_INSTANCE_IDX => C_VVC_ETH, GC_PHY_INTERFACE => GMII, GC_PHY_VVC_INSTANCE_IDX => C_VVC_GMII ); i1_gmii_vvc : entity bitvis_vip_gmii.gmii_vvc generic map ( GC_INSTANCE_IDX => C_VVC_GMII ) port map ( gmii_vvc_tx_if => gmii_vvc_tx_if, gmii_vvc_rx_if => gmii_vvc_rx_if ); Any VVC can be used as a physical interface, however it needs to have an HVVC-to-VVC Bridge implementation. You can find the available implementations under bitvis_vip_hvvc_to_vvc_bridge/src. For information on how to implement your own, see Bitvis VIP HVVC-to-VVC Bridge. VVC Implementation GuideImportant
Making test cases using available VVCs is very easy. Implementing new VVCs is slightly more complex, but fast, safe and efficient once you understand the VVC mechanisms.
Prerequisites
Implementing your new VVC
Dependent and independent sourceOne of the key concepts of the VVC Framework is the compilation strategy, and how some packages in the VVC Framework directory are compiled into each of the individual VVC libraries. To avoid confusion about this for future VVC designers, the VVC dependent and VVC independent sources have been marked and split into two source directories:
For examples of how the compile order should be handled, please see the example VIPs’ documentation and compile scripts. <name>_vvc.vhdEntity
The interface to the DUT and any other needed I/O. The examples show DUT interfaces as single signals, records and records of records. This is optional. Declarations
ConstructorThe constructor is run once only - immediately when starting the simulation. The procedure:
The procedure will report alerts with severity TB_FAILURE if one of the following occurs:
Command InterpreterWaits for commands from the central test sequencer distributed to this VVC, then puts the command on the queue for execution or immediately performs the required action - depending on command type. Afterwards, it acknowledges the command and waits for the next command from the sequencer. Step 0
-
initialize_interpreter(). Initializes parameters to default passive/initial values (e.g. terminate_current_cmd.set := ‘0’).- Initializes shared_vvc_last_received_cmd_idx.
-
priv_register_vvc(). Registers the VVC in the VVC activity register. This mechanism is used to detect whether a VVC is
active executing a command or inactive waiting for a new command, and is used by the await_completion mechanism.Step 1
-
await_cmd_from_sequencer()- Waits for a command from the central sequencer. Continues on matching VVC, instance index, name and channel.
- Log at start using ID_CMD_INTERPRETER_WAIT and at the end using ID_CMD_INTERPRETER.
- Will only accept exact matches of instance index and name, and either the correct address or “ALL_CHANNELS”.
- Updates shared_vvc_last_received_cmd_idx.
Step 2a (only if command type is QUEUED)
-
put_command_on_queue(). Puts the received command on the VVC queue (for later retrieval by the Command Executor).Step 2b (only if command type is IMMEDIATE)
- Execute the requested command/operation.
- For the VVC methods these procedures will correspond to the UVVM methods, but prepended with “interpreter_”, e.g.
“interpreter_fetch_result()”. These UVVM methods are documented in Common VVC Methods. Other commands are
documented in their respective VIPs.
- format_commmand_idx(): (ti_vvc_framework_support_pkg.vhd) Converts the command index to string, enclosed by C_CMD_IDX_PREFIX and
C_CMD_IDX_SUFFIX (found in uvvm_util/src/types_pkg.vhd).
Step 3
-
acknowledge_cmd(). Acknowledges the command from the sequencer by driving the global_vvc_ack signal to ‘1’ for 1 delta
cycle, then setting it back to ‘Z’. This lets the central sequencer know that it can continue execution.Command ExecutorFetches commands from the command queue - if any. Then executes the command and fetches or waits for the next command in the command queue. Step 0
-
initialize_executor(). Initializes parameters to default passive/initial values (e.g. terminate_current_cmd.reset := ‘0’).- Initializes the internal VVC scoreboard by setting up the scope, configuration and enabling it (only if the Scoreboard
feature was selected).
- Sets the randomization seeds (if applicable).
Step 1
-
update_vvc_activity_register- Updates the status of the VVC in the VVC activity register.
- It is set to INACTIVE right after the executor finishes with the current command.
- It is set to ACTIVE right after a new command is fetched from the command queue.
-
fetch_command_and_prepare_executor()- Fetches a command from the queue (waits until available if needed).
- Sets relevant flag parameters.
- Log command using ID_CMD_EXECUTOR (or log using ID_CMD_EXECUTOR_WAIT if queue is empty).
- Checks if the command is a BFM access
-
insert_inter_bfm_delay_if_requested()- Inserts either start-to-start or finish-to-start delay between BFM accesses if this is set in the inter_bfm_delay parameter
in ‘vvc_config’. Logs information using ID_CMD_EXECUTOR.
- If the command currently being processed by the executor is a BFM access, a timestamp will be stored in
v_timestamp_start_of_current_bfm_access.
Step 2
- Executes a command depending on the requested command/operation.
- The VVC Transaction Info is set before and after the command is executed with IN_PROGRESS and COMPLETED status.
- terminate_current_cmd is only checked inside operations that require multiple BFM accesses - like for instance a POLL_UNTIL
command.
-
store_result() is executed for any BFM, where it makes sense for you to store the result of a BFM access. In our example
for SBI we think it only makes sense for ‘READ’.- Logging as defined by your BFM.
- Updates the BFM access timestamps if this was a BFM access.
- v_timestamp_end_of_last_bfm_access is set to ‘now’.
- v_timestamp_start_of_last_bfm_access is set to v_timestamp_start_of_current_bfm_access.
- The terminate_current_cmd flag is reset if it has been active.
- Updates the last_cmd_idx_executed variable with the current command index (v_cmd.cmd_idx).
- Resets the VVC Transaction Info back to default values
Command TerminatorThe command terminator concurrent procedure sets the is_active flag based on the set and reset flags. Clock periodFinds the clock period of the clk signal. This is only necessary when there is a ‘valid’ signal, such as tvalid in the AXI4-stream protocol, in order to ignore a false trigger of the unwanted transaction detection mechanism. (Only if the Unwanted transaction detection feature was selected). Unwanted transactionMonitors unwanted transaction from the DUT. For more information see Unwanted Transaction Detection. (Only if the Unwanted activity detection feature was selected). Additional for multi-channel VVCsPlease note that we strongly recommend implementing the VVCs such that each leaf VVC handles one independent DUT communication thread (here: ‘channel’). No more; no less. This allows a single command queue and a single executor handling DUT communication. (Additional processes to handle other characteristics is fine. E.g., a parallel bit-rate check thread). Note that SBI_VVC must handle both read and write accesses, but never simultaneously and always in the given order. Multi-channel VVCs may be implemented in many different ways - depending on your preferences and priorities. Some examples are:
Figure 10 Multi-channel VVC examples When using multiple leaf VVCs it is recommended to use a wrapper architecture to encapsulate the channels. This way, it is possible to instantiate a single VVC rather than each VVC channel individually. For more information about the wrapper architecture, see the uart_vvc.vhd example in the bitvis_vip_uart/src/ directory. vvc_cmd_pkg.vhdt_operationContains all UVVM common operations, e.g. ENABLE_LOG_MSG and FETCH_RESULT, in addition to the VVC specific operations such as e.g. WRITE and READ. The VVC specific will have to be evaluated and potentially replaced when implementing a new VVC. The t_operation type is used when relaying commands from the sequencer to the VVC. Note If the VVC transaction info feature was selected, this type is defined in the transaction_pkg.vhd instead. ConstantsIn this package we can define constants that need to be set for the entire VVC. In most VVCs this will include the C_VVC_CMD_STRING_MAX_LENGTH which determines the maximum size of msg variables in the VVC. It is also a good idea to declare constants for maximum VVC data/address bus sizes here. It will be possible to construct VVCs with bus sizes up to and including the sizes declared here. Note If the VVC transaction info feature was selected, these constants are defined in the transaction_pkg.vhd instead. t_vvc_cmd_recordRecord type used for relaying a command from the testbench sequencer to the VVC. The record contains fields needed in the Common VVC Methods, and VVC specific fields needed to relay data to the VVC executor. There is a default constant for this type called C_VVC_CMD_DEFAULT in this package. The VVC mandatory data fields are the following:
The VVC specific data fields should contain any data fields that the BFM procedures might need, e.g. data, address, timeouts etc. Shared VariablesThe shared variable The shared variable The shared variable FunctionsA custom to_string() function can be defined in this package if the t_vvc_result is a record type. vvc_methods_pkg.vhdConstants and aliasesThe vvc_methods_pkg contains a constant for the VVC name, e.g. “<NAME>_VVC”. There are also aliases created to make the code more readable. <NAME>_VVCTThe <NAME>_VVCT signal (e.g. SBI_VVCT) is the VVC target record signal. The target type t_vvc_target_record is a record that contains the parameters needed to trigger a VVC, and to identify the correct target of a VVC command. t_vvc_configThis type contains the needed configuration for setting up the VVC and BFM. In Bitvis VVCs the BFM configuration is encapsulated in a bfm_config record, of type t_<bfm_name>_bfm_config. This record is placed in this file and compiled into each VVC since the VVC/BFM configuration will differ for each VVC. The record contents are:
A constant C_<NAME>_VVC_CONFIG_DEFAULT is defined for this type to use as default value. t_vvc_statusThe optional status record is created in order for the testbench sequencer to have access to the status of the VVC. The status record can contain anything that is relevant for the outside, and it is recommended to have at least these three fields:
A constant C_VVC_STATUS_DEFAULT is defined for this type to use as default value. Shared VariablesA shared variable array A shared variable array The internal VVC Scoreboard VVC Dedicated MethodsThe vvc_methods_pkg.vhd file also contains the VVC procedures that are called from the testbench sequencer. These procedures should reflect the procedures in the BFM, e.g. <name>_write or <name>_receive. The parameters of these procedures are mostly up to the user, but it is recommended that the BFM arguments that are rarely altered be placed into the bfm_config parameter, while the parameters that changes often are used as input arguments. Since these VVC methods are reused for all instances of this VVC, it is necessary with some extra parameters in order to specify which VVC instance to forward the call to. This is done with the first two (or three) parameters: signal VVCT : inout t_vvc_target_record; constant vvc_instance_idx : in integer; constant channel : in t_channel; -- Only if the VVC is multi-channel. The method bodies are quite similar for all VVC commands:
All VVC instances and channels of this type receive the command, but only the VVC with the correct instance index, channel and name will accept it and acknowledge it. Transaction info MethodsThis package also contains two procedures, set_global_vvc_transaction_info() and reset_vvc_transaction_info(). These procedures
are used to store the necessary information from the VVC command into the shared variable transaction_pkg.vhd(This package is only generated if the VVC transaction info feature was selected). t_operationContains all UVVM common operations, e.g. ENABLE_LOG_MSG and FETCH_RESULT, in addition to the VVC specific operations such as e.g. WRITE and READ. The VVC specific will have to be evaluated and potentially replaced when implementing a new VVC. The t_operation type is used when relaying commands from the sequencer to the VVC. Note If the VVC transaction info feature was NOT selected, this type is defined in the vvc_cmd_pkg.vhd instead. ConstantsIn this package we can define constants that need to be set for the entire VVC. In most VVCs this will include the C_VVC_CMD_STRING_MAX_LENGTH which determines the maximum size of msg variables in the VVC. It is also a good idea to declare constants for maximum VVC data/address bus sizes here. It will be possible to construct VVCs with bus sizes up to and including the sizes declared here. Note If the VVC transaction info feature was NOT selected, these constants are defined in the vvc_cmd_pkg.vhd instead. Global signals and shared variablesThe global signal The shared variable See Distribution of Transaction Info - From VVCs and/or Monitors for more details on the types used and basic concepts. vvc_sb_pkg.vhd(This package is only generated if the Scoreboard feature was selected). This file contains two packages. First, the vvc_sb_pkg is a package declaration from the generic_sb_pkg using the VVCs data type as the t_element generic type and the corresponding functions for element_match and to_string_element generics functions. It also contains the vvc_sb_support_pkg, which contains the function pad_<name>_sb() to pad the data without having to know the exact length of t_element. This is useful because the data parameter used in the scoreboard procedures must have the same length as the t_element defined in the VVC’s built-in scoreboard, which even though is a generic type, it is constrained during elaboration time. vvc_context.vhdThis file contains all the necessary packages that are used when simulating a VVC. When adding a VVC to a testbench, the user only needs to add the following lines in the header: library bitvis_vip_<name>; context bitvis_vip_<name>.vvc_context; The generated file from the vvc_generator script has the following as default:
Additional types or constants can be added if needed. BFM prerequisitesThere are no firm restrictions of how to implement the BFM in order for the VVC to function, but if the VVC generated with the vvc_generator script is to work out of the box, it is necessary to have some components in the BFM:
A BFM skeleton that contains the necessary structure is created by the vvc_generator script, and can be used as a base for a BFM that includes the necessary structure for the VVC to work out of the box. VVC Framework Packagestd_target_support_pkg.vhdThe UVVM VVC dedicated support package contains VVC support that is common for all VVCs, but needs to be compiled specifically into each of the VVC libraries. Target recordThe target record type t_vvc_target_record is used to target a VVC command to a specific VVC implementation. This is needed since many of the UVVM common commands are shared between all VVCs, e.g. await_completion() which is compiled into each VVC library. For a sequencer with two VVCs, A and B, there must be a way of determining if await_completion is to be executed in VVC A or VVC B. To resolve this, each VVC has a signal in their vvc_methods_pkg.vhd that is compiled into their own library. For VVC A and B this signal will be called A_VVCT and B_VVCT. When await_completion(A_VVCT,…) is called from the sequencer, the compiler will understand that this await_completion is called with target type library_a.t_vvc_target_record, which only complies with the await_completion procedure in the VVC A library. The td_target_support_pkg.vhd also contains a default value for the t_vvc_target_record type, and a function set_vvc_target_defaults() for setting the VVC target based on the VVC name. String methodsThe package contains two string methods:
send_command_to_vvcSends command to VVC and waits for ACK or timeout.
Setting the command fieldSets target index and channel, and updates shared_vvc_cmd which is used to transport VVC commands from the central testbench sequencer to VVC. td_vvc_entity_support_pkg.vhdThe VVC support package contains procedures that are compiled into and used in the VVC. This includes initializers for the executor and interpreter, and the interpreter procedures called interpreter_*, e.g. interpreter_fetch_result(). For more information about the interpreter_* procedures, please see Common VVC Methods. For more information about the other methods in this package, see <name>_vvc.vhd. In addition to the procedures, the td_vvc_entity_support_pkg.vhd also contains types for VVC labels. VVC Generator scriptQuick Summary
IntroductionThe VVC Generator is a Python 3 script that generates VVCs and accompanying support files, including the command package, methods package, a BFM skeleton and if necessary, a VVC wrapper for multi-channel VVCs. PrerequisitesIn order to run the script, it is necessary to have Python installed. To run the script from the command line, the python interpreter path needs to be added to the Path environmental variable. Only Python 3 is supported. Running the scriptThe script can be run from the command line by running: The script will query the user for information about the VVC during the script:
When the script has gathered all the information it needs, it will generate the VHDL files in the ‘output’ directory. The naming of the files will be (<name> is the VVC name, and <channel> is a channel name):
Modifying the created VHDL filesAfter the script has completed, the files need some user interaction before they are ready to use. In all places marked with “--<USER_INPUT>” there will be instructions on how to properly modify the VVC for your BFM. Additionally, if you created a VVC with multiple channels, please make sure to add these channels to the t_channel type located in the UVVM-Util adaptations_pkg.vhd file. By default, this type only contains ‘TX’ and ‘RX’ channels but more can be added to fit any project. TI VVC Framework Support PackageType definitions used in the VVC Framework. TI Protected Types PackageProtected type definitions used in the VVC Framework. Note Disclaimer: This IP 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 non-infringement. 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 this IP. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| You are visitor 01402503 — GeezerVison does not store the pages you look up. Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||