UVVM VVC of a simple counter (having issues getting it to simulate with counter_vvc in place)

Hi,

I am new to the UVVM VVC creation.

I am trying to convert my current verification platform to using VVC. I generated the templates by executing the python vvc_generator.py for my counter DUT.

Looked at the following link which has a simple counter and tried to follow same approach like they do to build the UVVM platform with VVC in place

 https://www.edaplayground.com/x/2LhW

This simple counter design.vhd, testbench is not complete ie test sequencer process is missing calling the procedural commands etc

I am using a different counter as my DUT to this one just incrementing and reseting.

Used gen_pulse within my testbench to create an active high pulse for the reset. This works ok. Reset connects directly to the DUT (counter) within the test harness (ie it is not part of my counter_vvc). This reset pulse works fine.

Instantiated also within my testbech the bitvis clock_generator_vvc. This works fine too.

I created a BFM procedure counter_count_up and placed this within the counter_bfm_pkg

I called this counter_count_up procedure within my testbench Test Sequencer process and the counting up works fine right after reset (this is without the VVC framework in place).

The counter_count_up procedure just generates an active high enable signal (out) and counts up. It also does self checking of the counter at various points using the check_value uvvm utils procedure. Simulated this without the counter_vvc first in place and that was ok.

However, having problems at the moment when I added the BFM procedure call in the counter_vvc within the VVC dedicated operations. case v_cmd.operation COUNT_UP was used for this and within vvc_cmd_pkg.vhd I included COUNT_UP within the t_operation type list.

The clk is visible but the counter_vvc counter interface ‘in_enable’ and ‘out_counter’ interface signals do not perform as expected.

The template counter_vvc.vhd included a constructor, command interpreter, command executor and command termination handler. It is my understanding that the only things I need to add in this template file is to Insert BFM procedure calls within the case v_cmd.operation and update the top-level port of the counter_vvc to insert BFM interface signals. Isn’t this the case?
Do I need to create a Config initializer process (like the clock_generator_vvc does)?

I also noticed that the vvc_methods_pkg.vhd examples VVC procedure declarations inserted in this file just include example the following:

– <USER_INPUT> Please insert the VVC procedure declarations here

procedure counter_cnt_up (
signal VVCT : inout t_vvc_target_record;
constant vvc_instance_idx : in integer;
constant cycles : in natural;
constant msg : in string
);

ie it includes VVCT signal and not the original interface signals. Is this correct? Can someone explain here this matter too.

Within the package body of vcc_methods_pkg included the following which included the COUNT_UP:

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
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;


The main issue I have is that the ‘in_enable’ is low at the beginning as expected BUT as soon as this signal tries to go to ‘1’ from the counter_count_up BFM procedure after executing the following command within the testbench:

counter_count_up(0, “Enable the counter to start counting up”, in_clock, in_enable, out_counter, C_SCOPE);**

the in_enable line is ‘X’ and stays 'X’

Initially had my in_enable signal declared as input port at the test harness level but had the following compilation error:

"Cannot assign to object ‘in_enable’ of mode IN

Changed it then top level test harness in_enable from input to output port. Then after running the simulation it shown this ‘X’ propagation issue on the ‘in_enable’ when the above command was executed from the testbench (test sequencer process).

in_enable is input to the DUT (counter). Test harness also instantiates the counter_vvc module and connected there the clock, reset, in_enable & out_counter.

This is URGENT. Prompt reply to this matter will be appreciated

Regards,

Kevin

Hi Kevin,

I’ve just had a short test using the VVC in your testbench and the counter seems to work (only showing the code I’ve added to your testbench):

log(ID_SEQUENCER, "Resetting counter", C_SCOPE);
counter_reset(COUNTER_VVCT, 1, "Reset counter value");
await_completion(COUNTER_VVCT, 1, 2*C_CLK_PERIOD, "Await execution");

-- verify counter value
counter_check(COUNTER_VVCT, 1, x"00", "Checking counter reset value");

log(ID_SEQUENCER, "Loading counter value x01", C_SCOPE);
counter_load(COUNTER_VVCT, 1, x"01", "Loading counter value x01");
await_completion(COUNTER_VVCT, 1, 2*C_CLK_PERIOD, "Await execution");

-- verify counter value
counter_check(COUNTER_VVCT, 1, x"01", "Checking counter value");

log(ID_SEQUENCER, "Counting up 5 clock periods", C_SCOPE);
counter_count_up(COUNTER_VVCT, 1, 5, "Counting up 5 cycles");
await_completion(COUNTER_VVCT, 1, 5*C_CLK_PERIOD, "Await execution");

-- verify counter value
counter_check(COUNTER_VVCT, 1, x"06", "Checking counter value");

log(ID_SEQUENCER, "Simulation finished", C_SCOPE);
-- done
wait for C_CLK_PERIOD;

-----------------------------------------------------------------------------
-- Ending the simulation
-----------------------------------------------------------------------------

This is how the wave view looks like

Br,
Marius

Hi Marius,

The key to my VVC issue was that I was trying to call in my Testbench the BFM procedure of counter_count_up and not the VVC related one (VVC one uses paramerers such as eg COUNTER_VVCT set within it etc).

Your short test of commands gave me this clue (understanding). Managed to get my counter going. I was using the check_value uvvm_utils procedure checking out my counter values. Could create my own counter_check one which could check a bigger range of values in one go.

I could see also the UVVM Counter Testbench Example - EDA Playground counter example now working. My counter as mentioned in my previous message is different than this one.

Kind regards,
Kevin

Great,
You should be able to call the BFM procedures from the testbench sequencer as well. The sequencer code will have to be changed obviously, as the BFM procedures will block/stall the sequencer while the procedure is being executed.

Br,
Marius

Hi Marius,

For the VVC platform I have ie included VVC procedure declarations & implementations within the vvc_methods_pkg.vhd the implementation (ie wiggling of the counter DUT signals) is done in my counter_bfm_pkg.vhd package body part.

Currently, within my counter_vvc.vhd v_cmd.operation state machine I inserted the BFM procedure calls for eg COUNT_UP case included the counter_count_up (ie this calls the corresponding procedure counter_count_up in the BFM package counter_bfm_pkg.vhd). Is this expected here?

VVC procedures framework looks to interact with the BFM procedures to acquire info about the DUT interface signals wiggling. Is this the case?

Can this interface wiggling signals be done at the VVC procedures level without requiring the BFM procedures? or is it easier to do it this way ie develop first BFM procedures and then re-use them within the VVC framework structure.

Your comments on this matter will be appreciated.

Regards,
Kevin

Hi,
The pin wiggle should be done by the BFM, and when you have a VVC, it will be responsible for calling the BFM procedure. This way your test sequencer is free to perform several tasks in parallell, e.g. call another VVC to perform some other work, or maybe do some logging, checking etc.

Br,
Marius

Great. Thanks. This is how I implemented it and I will leave it like this.

This was a question asked by one of my colleagues today when I presented my UVVM VVC testcase to them

1 Like

Hi Marius,

Another question. We will like to incorporate PASS/FAIL reporting into the UVVM platform scripts.
I have initially included within my testbench ‘check_value’ UVVM utils procedure to check the counter at various points.

eg
check_value(x"0002", out_counter(1), TB_ERROR, “Checking out_counter(1) value5”, C_SCOPE);

If the accepted (ie expected) value is x"0002" and the captured out_counter(1) value at that point is x"0002" then within simulation/modelsim directory currently see _Alert.txt file empty. However, if a TB_ERROR is detected then it will report it within the _Alert.txt.

We will also like to be able to report the following info into eg a log file using UVVM command features (if possible). Will be looking to add this feature too into my scripts. Any initial thoughts wrt existing UVVM commands that can achieve this will be appreciated.

module name procedure name accepted value captured value Result

Counter check_value ? x"0002" x"0002" PASS
Counter check_value ? x"0003" x"0002" FAIL
:::


Wrt the extended UVVM features for the generated VVC, I did not enable these options yet as reported previously:

  • Enable scoreboard
  • Activity watchdog & transaction info

Kind regards,

Kevin

Hi,
You could use the checker functions, e.g.
variable v_check_ok : boolean;

v_check_ok := check_value(…);
if v_check_ok = False then

See section 1.1 in the Utility Library Quick Reference for various checker implementations.

Note that you can change the number of expected (TB_)ERROR, (TB_)WARNING etc, and also set the stop limit - e.g. set_alert_stop_limit(TB_WARNING, 2); – stop sim after 2 TB_WARNING (see section 1.3 in the Utility Library QR)

And you can use the report function - report_alert_counters(FINAL); - which will present the number of alerts detected vs expected, and report a simulation PASS/FAIL based on this (see final line in the report):

Br,
Marius

Hi Marius,

Thanks. Haven’t used v_check_ok variable yet because I noticed that the simulation as soon as it finds 1 error it stops immediately reporting where the error was and does not continue until the end of the simulation where I can report pass/fail on each of the check_value commands used within the testbench.

I then added the following at the top of the p_main testbench process:

increment_expected_alerts_and_stop_limit(TB_ERROR,3,“Expecting 3 more TB_ERRORS”);

Is this the Alert handling function you meant to suggest?

This allowed the tool to carry on and complete the whole simulation process reporting all the alert results at the end. In this example I introduced 1 TB_ERROR to one of the check_value calls.

Tried also the following:

increment_expected_alerts_and_stop_limit(TB_ERROR,0,“Expecting 0 or more TB_ERRORS”);

After compiling the testbench, it did not report any testbench compilation warnings here, so 0 looks to be a valid parameter too (and it stopped the simulation as soon as 1 TB_ERROR was found).

Ideally, we will like to catch all TB_ERRORS in the testbench and report at the end all PASSes & FAILs. Can we eg disable the expected alert TB_ERROR stop limit ?

In the example above, used a value of 3 within the increment_expected_alerts_and_stop_limit()
but if there are eg 3 recorded in this example, the simulation will stop.

Like to avoid using a large number eg 100 and keep changing it to a bigger value, if it reaches it ie 100 or more TB_ERRORs …

Kind regards,
Kevin

Hi Marius,

I managed to disable the expected alert TB_ERROR stop limit by using the following command instead of the increment_expected_alerts_and_stop_limit() one :

set_alert_stop_limit(TB_ERROR, 0);                -- 0 means never stop

Will like if I start using the v_check_ok variable as you suggested to then dump the PASS/FAIL results in an output file with a certain reporting structure (similar to what TEXTIO Write does)

Regards,
Kevin

Hi Kevin,
Yes, you can disable the alert to allow for the TB to run through all the simulations without stopping.

Br,
Marius

Hi Marius,

To write to a log file the correct structure we will like, I added WRITE TXT IO instructions as shown in the example below right after each v_check_ok := check_value(xxx) statement. I also included opening an “out.txt” in WRITE_MODE at the top of the testbench and a loop (looping once) at the beginning writing the top header part (not shown the whole code below).

eg
WRITE(L, string’(“Sim time: Module’s name: Procedure name: Accepted value: Captured value: Result”));

I have also used: report_alert_counters(FINAL) and this displays a final summary of all Alerts but this is displayed in the uvvm format not the format we will like (but I included this as well at the end of the testbench to report this too - useful to have). Any comments here too will be appreciated.

Testbench got much bigger in size by adding the individual WRITE procedure commands right after each
v_check_ok := check_value(xxxx)

Ffi see my example below.

If I can move each block of the WRITE procedure commands to 1 procedure call this could shorten the procedure calls added into my testbench or use any other single uvvm procedural calls replacing the WRITE ones I used that would be great. Looking into this matter too but if you have any comments on this matter please let me know.

eg

:::

v_check_ok := check_value(x"0099", out_counter(0), TB_ERROR, “Checking out_counter(0) value4”, C_SCOPE);

WRITE(L, NOW, left, 15);
WRITE(L, string’(“Counter”), right, 17);
WRITE(L, string’(“check_value”), right, 17);
WRITE(L, string’(“0x0099”), right, 16);
WRITE(L, string’(“0x”) & to_hstring(out_counter(0)), right, 21);

if v_check_ok = false then
WRITE(L, string’(“FAIL”), right, 19);
WRITELINE(F, L);
ErrCnt <= ErrCnt + 1;
else
WRITE(L, string’(“PASS”), right, 19);
WRITELINE(F, L);
TotalPass <= TotalPass + 1;
end if;

TotalCnt <= TotalCnt + 1;
wait until rising_edge(in_clock);

:::

Regards,
Kevin

Hi Kevin,
Keeping the summary report is fine I think.

It would definitely be an improvement to the testbench sequencer readability if you put the check, counter updates and all of the write commands in a dedicated procedure that is called from the sequencer.

Br,
Marius

Hi Marius,

Wondering whether the counter updates and the WRITE commands can be done with uvvm util procedures than having to create mine (time consuming) using eg the ‘log’ procedure to display the main header string and any other ready made uvvm procedures to display the text numeric results within the right columns including PASS/FAIL.

Your reply to this matter will be appreciated.

Regards,
Kevin

Hi,
You can use the util procedures, but you should create a procedure/function that calls them and not make changes in the procedures. See section 1.2 about logging in the Utility Library QR. E.g

  -- TB locally declared function (or put in a package)
  function check_and_log(
    constant exp_value : std_logic_vector;
    constant act_value : std_logic_vector) 
  return boolean is
    variable v_check_ok : boolean;
  begin
      v_check_ok := check_value(exp_value, act_value, TB_ERROR, "checking DUT output", C_SCOPE);
      if v_check_ok = false then
        log(....... FAIL);
      else
        log(......PASS);
      end if;
      return v_check_ok;
    end function check_and_log;

-- select log file in the start of the sequencer
set_log_file_name("counter_checker_log.txt");

...

-- call function from inside loop in the sequencer
v_ok := check_and_log(exp_value, act_value);

if v_ok = false then
  err_cnt := err_cnt + 1;
end if;
-- pass_cnt = tot_cnt - err_cnt

Something like this.

Br,
Marius

Hi Marius,

Thanks for your suggestion.

If I use the check_value within the function check_and_log (this function was placed in a package), I get the following warning:

** Warning: (vcom-1285) Cannot call impure function “check_value” from pure function “check_and_log”.

Does the check_and_log need to be a procedure instead of a function?

Kind regards,
Kevin

Hi,
Just make it an impure function.

Br,
Marius

Hi Marius,

That’s what I thought too afterwards :-). Made it as an impure function and it worked ok. Thanks.

I have now a counter_check_log.txt file reporting the the UVVM commands:

eg

UVVM: ID_SEQUENCER …
UVVM: ID_CMD_INTERPRETER_WAIT …
UVVM: ID_CMD_EXECUTOR_WAIT …
UVVM: ID_CMD_INTERPRETER …
UVVM: ID_CMD_EXECUTOR …
::

UVVM: ID_SEQUENCER 11300.0 ns CLOCKCYCLECOUNTER BFM Module’s name: ClockCycleCounter | Procedure name: check_value
UVVM: ID_SEQUENCER 11300.0 ns CLOCKCYCLECOUNTER BFM Accepted value: 00000000000001100011 | Captured value: 0000000001100011 | Result PASS

UVVM: ID_SEQUENCER 11400.0 ns CLOCKCYCLECOUNTER BFM Module’s name: ClockCycleCounter | Procedure name: check_value
UVVM: ID_SEQUENCER 11400.0 ns CLOCKCYCLECOUNTER BFM Accepted value: 0000000000000000 | Captured value: 0000000000000000 | Result PASS

::

UVVM: ID_SEQUENCER 6573100.0 ns CLOCKCYCLECOUNTER BFM Module’s name: ClockCycleCounter | Procedure name: check_value
UVVM: ID_SEQUENCER 6573100.0 ns CLOCKCYCLECOUNTER BFM Accepted value: 0000000000000010 | Captured value: 0000000000000001 | Result FAIL

:::

UVVM: ID_SEQUENCER 6573200.0 ns TB seq. Summary- | Total test = 10 | Total pass = 9 | Total fail = 1


Within the testbench I specifically instructed it to do the following:

disable_log_msg(ALL_MESSAGES);
enable_log_msg(ID_SEQUENCER);

but it displayed within the counter_checker_log.txt all the other commands too.

Will like to filter everything out and just log the following:

UVVM: ID_SEQUENCER xxx CLOCKCYCLECOUNTER BFM xxx +
UVVM: ID_SEQUENCER xxx TB seq. xxx just the last summary report which shows the Total PASS/FAIL.

Looking to use PowerShell to do this at the moment but if you have any other suggestions eg using specific UVVM instructions to do it please let me know.

Kind regards,
Kevin

Hi Marius,

Used PowerShell and got it to report what I wanted. But found a better way to do it using the ‘log’ procedure.

Managed to get it reporting to a .txt file the lines I want by incorporating within the ‘log’ procedure extra parameters such as “MyScope”, shared_msg_id_panel, LOG_ONLY, “counter_checker_myscope_log.txt”, append_mode

Kind regards,
Kevin