UVM end of test - system-verilog

In case I want to end the simulation from my monitor (I know that it is not the recommended way) how can I do this?
lets say I got this code inside my monitor:
Virtual task monitor_run();
fork
forever begin
.....
end
forever begin
.....
end
forever begin
.....
end
join
endtask : monitor_run
Every forever loop check that outputs of the DUT came on time, in case they doesnt it should stop simulation.
This special monitor should break the simulation in case of mismatch(error) and there is no Scoreboard.
I still want to manage nice end of simulation behaviour. I tried use raise and drop objection but I get an error of OBJT_ZERO sometimes. Does anyone knows a good way to end the simulation in that case?
thanks!

The UVM is set up by default so that uvm_report_fatal ends the test immediately, and uvm_report_error lets the simulation continue until hitting an error limit that you can set. And you can control the actions of each severity for an individual component. See uvm_report_object which is the base class of uvm_component.
Upon ending the test, the UVM calls uvm_report_server::report_summarize() that dumps out all the severity counts. If you insist, you can create a final block in your testbench module that gathers the severity counts from the report server and print the last message. For example:
module top;
initial run_test();
uvm_report_server rs = uvm_report_server::get_server();
final if (rs.get_severity_count(UVM_FATAL) != 0 ||
rs.get_severity_count(UVM_ERROR) !=0 )
$display("Test Failed");
endmodule
But this is really unnecessary and may not catch other non-UVM errors like assertion failures or timing checks. Many tools have a TESTSTATUS exit code that reports the most severe message encounte, UVM or tool.

Related

How to check in SystemVerilog that signal went high during simulation using ModelSim

I need to check, whether during the testbenching the particular signal went at least for a single clock cycle to logic 1.
I've tested following asserts, which shall be equivalent:
initial assert property (
#(posedge clk_tree_x.ClkRsBST_ix.clk)
s_eventually TS.TSUpdated) else
$error("Was not active");
and
initial begin
assert property (#(posedge clk_tree_x.ClkRsBST_ix.clk)
strong(##[*] TS.TSUpdated)) else
$error("Was not active");
end
In simulation using Mentor ModelSim SE64 2021.1 the results are extremely weird.
On first simulation pass the simulation completely ignores this assert. On second simulation pass ModelSim apparently uses results of previous simulation to announce before even the newly run simulation happens that the assert triggered:
# Time: 2005087500 ps Started: 5 ns Scope: tb_bst_provider.DUT.fook File: bst_provider.sv Line: 669
# ** Warning: (vsim-8777) Breakpointing based on severity while evaluating concurrent assertion is not supported.
# Time: 2005087500 ps Iteration: 0 Region: /tb_bst_provider/DUT File: bst_provider.sv
Not sure whether this is consistent behaviour to all strong properties, but it is hardly useful for any sort of unit testing, as the tests never run twice using the same parameters.
Is there any way how to assert that 'signal is not present through the simulation run', which actually works with modelsim?
I am not sure if you can do it with an assertion. You can detect not active signal using an assertion coverage. In any case you should not place an assertion in the initial block.
Potentially checking for activity can be done without using an assertion as in the following example.
always #(posedge clk) begin
if (sig == 1)
active <= 1;
end
final begin
if (!active)
$error("was not active");
else
$info ("it was active");
end
Just make sure that you have a normal exit from simulation or final might not be executed at all in case of interrupts.

How to modify bit bash sequence for write delays and read delays of DUT?

I have a DUT were the writes takes 2 clock cycles and reads consume 2 clock cycles before it could actually happen, I use regmodel and tried using inbuilt sequence uvm_reg_bit_bash_seq but it seems that the writes and reads happens at 1 clock cycle delay, could anyone tell what is the effective way to model 2 clock cycle delays and verify this, so that the DUT delays are taken care.
Facing the following error now,
Writing a 1 in bit #0 of register "ral_pgm.DIFF_STAT_CORE1" with initial value 'h0000000000000000 yielded 'h0000000000000000 instead of 'h0000000000000001
I have found one way of doing it, took the existing uvm_reg_single_bit_bash_seq and modified by adding p_sequencer and added 2 clock cycle delays after write and read method calls as per the DUT latency, this helped me in fixing the issue as well added a get call after write method to avoid fetching old value after read operation.
...
`uvm_declare_p_sequencer(s_master_sequencer)
rg.write(status, val, UVM_FRONTDOOR, map, this);
wait_for_clock(2); // write latency
rg.read(status, val, UVM_FRONTDOOR, map, this);
wait_for_clock(2); // read latency
if (status != UVM_IS_OK) begin
`uvm_error("mtm_reg_bit_bash_seq", $sformatf("Status was %s when reading register \"%s\" through map \"%s\".",
status.name(), rg.get_full_name(), map.get_full_name()));
end
val = rg.get(); // newly added method call (get) to fetch value after read
...
task wait_for_clock( int m = 1 );
repeat ( m ) begin
#(posedge p_sequencer.vif.CLK);
end
endtask: wait_for_clock
...

How to get the status of property in the RTL

In some scenarios, injecting error will trigger the assert to be fail. so , I pass the switch to turn off this assert by $testplusargs. Is there a way to get the status of property(vacuous true, real true or fail) at the end of test cases, for example by PLI or other ways supplied by simulator(I am using vcs). Anyone has some idea for this? Thanks a lot.
You can register some VPI callbacks to the assertion and check the number of failed/passed counts.
You could also in system verilog count number of pass/fail of the property with the action blocks.
For example :
assert property(p_test) begin
pass_cnt++;
end else begin
fail_cnt++
end

Confusion regarding usage of event.triggered

I'm trying out some code that is supposed to block until moving to a new simulation time step (similar to waiting for sys.tick_start in e).
I tried writing a function that does this:
task wait_triggered();
event e;
`uvm_info("DBG", "Waiting trig", UVM_NONE)
-> e;
$display("e.triggered = ", e.triggered);
wait (!e.triggered);
`uvm_info("DBG", "Wait trig done", UVM_NONE)
endtask
The idea behind it is that I trigger some event, meaning that its triggered field is going to be 1 when control reaches the line with wait(!e.triggered). This line should unblock in the next time slot, when triggered is going to be cleared.
To test this out I added some other thread that consumes simulation time:
fork
wait_triggered();
begin
`uvm_info("DBG", "Doing stuff", UVM_NONE)
#1;
`uvm_info("DBG", "Did stuff", UVM_NONE)
end
join
#1;
$finish(1);
I see the messages Doing stuff and Did stuff, but Wait trig done never comes. The simulation also stops before reaching the finish(1). One simulator told me that this is because no further events have been scheduled.
All simulators exhibit the same behavior, so there must be something I'm missing. Could anyone explain what's going on?
The problem is with wait (!e.triggered); when e.triggered is changing from 1 to zero. It has to change in a region where nothing can be scheduled, so whether it changes at the end of the current time slot, or the beginning of the next time slot is unobservable. So the wait will hang waiting for the end of the current time slot, which never comes.
I think the closest thing to what you are looking for is #1step. This blocks for the smallest simulation precision time step. But I've got to believe there is a better way to code what you want without having to know if time is advancing.

Is there a way to assert that all signals in a design are initialized on rising clock during reset?

Just from the tester flow (no changes to design) is there a quick way to assert that all the design signals are initialized during reset?
Design uses synchronous active low reset.
On the rising edge of reset I want to assert that every signal in the design is not 'U' without having to call out each signal or architecture.
Using VHDL 2008, Modelsim 10.1c with HDL Designer.
You can adapt the use of the Modelsim when command from this answer to look for 'U' in any signals after the synchronous reset is released. As it exists it works with scalars and arrays but cannot examine record members.
Note that the rising edge of reset is not the time that reset is released since you are using synchronous reset. I would make the test wait for the first falling edge of clock when reset is high to test for 'U'. This will ensure that you see the new state on signals when their drivers update after the reset. The when expression would be something like:
"clk'event and clk = '0' and reset = '1' and $sig = [string repeat U [string length [examine $sig]]]"
Another option would be to create a sentinel signal in the testbench that evaluates to true when reset is released and test for that in the when expression:
signal reset_inactive : boolean;
process(clk) is
begin
if rising_edge(clk) then
if reset = '1' then
reset_inactive <= true;
else
reset_inactive <= false;
end if;
end if;
end process;
...
When expression:
"reset_inactive'event and reset_inactive = true and $sig = ..."
Once complete it would be a good idea to cancel the waits with the nowait command to avoid the performance hit of having a wait on every signal in the design since you only need this test after reset.