I am trying to put a concurrent assert statement inside of a task which is within a class, but it is giving me an error that says “SystemVerilog assertion, property or sequence declarations are illegal as a function declaration item”
When I put the assertion inside the interface instead of inside my class, it works. Is there a way to do it here inside this task?
task generate_video_pattern();
begin
// Write Windows size
write_reg(WINDOW_SIZE_X, WINDOW_SIZE_X_ADDR);
write_reg(WINDOW_SIZE_Y, WINDOW_SIZE_Y_ADDR);
//write to the control reg to enable test pattern
this.write_data = 32'h1;
write_reg(this.write_data, CONTROL_REG_ADDR);
// m_axis_tlast should go high 4 clock cycles after m_axis_tuser_sof
property TLAST_FLAG;
@(posedge vpattgen_if.axis_aclk) (vpattgen_if.m_axis_tuser_sof |-> ##4 vpattgen_if.m_axis_tlast);
endproperty
assert_tlast_flag: assert property (TLAST_FLAG) $display("[%0t ns] assert passed", $time);
else $display("[%0t ns] assert failed", $time);
end
endtask
endclass
endpackage
In reply to ianmurph: Concurrent assertions are DISALLOWED in tasks or in classes because they are dynamically instanced. However immediate assertions are legal.
Since your assertion impact interface signals, your best bet is to put the concurrent assertions in the interface. However, there is a mechanism to emulate concurrent assertions in classes using tasks. I explain this in my paper Understanding the SVA Engine, https://verificationacademy.com/verification-horizons/july-2020-volume-16-issue-2
Thanks for the reply. I am reading your paper now, but emulating the concurrent assertion using a task might be a bit over my head. I could leave it in the interface file, but we are using a scoreboard to monitor pass/fails, so I might just stick to immediate assertions.
I attempted a workaround where the assertion in the interface sets an error bit, and then I try to read that error bit from my task inside my testcase class, but this doesn’t work. Can you explain to me why this doesn’t work? It seems like assertion_error doesn’t get set - if I use a signal of type ‘bit’, it always prints ‘0’ to the console. If I use signal type ‘logic’ it always prints ‘x’ to the console.
Assertion inside interface file:
//Assertions
bit assertion_error;
// m_axis_tlast should go high WINDOW_SIZE_X - 1 clock cycles after m_axis_tuser_sof
property TLAST_FLAG;
@(posedge axis_aclk) (m_axis_tuser_sof |-> ##4 m_axis_tlast);
endproperty
assert_tlast_flag: assert property (TLAST_FLAG) assertion_error = 0;
else assertion_error = 1;
endinterface
Reading the error bit inside my testcase class task:
$display("The value of assertion_error is: %0b", vpattgen_if.assertion_error);
end
endtask
Can you explain to me why this doesn’t work? It seems like assertion_error doesn’t get set - if I use a signal of type ‘bit’, it always prints ‘0’ to the console. If I use signal type ‘logic’ it always prints ‘x’ to the console.
I address your topic of writing assertions in interfaces and reading the violations or results in the class.
Definitely read that paper. From the paper:
…
SVA handles cycle accurate checks more effectively than with an application using scoreboarding because the verification of the signals is done at every cycle rather than at the completion of the data gathering process. The action block of an assertion can modify SystemVerilog interface variables or static class variable on either a pass or a fail action of the assertion. Those variables can then be used by a class instance to drop an objection or to modify the flow of the class. Figure 2.0 demonstrates these concepts. Figure 2.0 Using the results of an assertion to stop the simulator3 http://SystemVerilog.us/verizons/sc2uvm.sv
…
Ben
We really can’t help more without seeing how the signals in your interface get their values. (i.e. are there any race conditions that might affect how you think the values should be interpreted?)
You could write a similar piece of behavioral code
always begin
@(posedge axis_clk iff m_axis_tuser_sof)
$display("antecedent happens",, $time);
repeat(4) @(posedge axis_clk)
if(m_axis_tlast)
$display("assertion should have passed");
else
$display("assertion should have failed");
end
That would not work because you would sample the m_axis_tuser_sof every 4th clock if that variable is true. You would have to use what I suggested in my paper Understanding the SVA Engine..
task automatic t();
@(posedge axis_clk iff m_axis_tuser_sof)
$display("antecedent happens",, $time);
repeat(4) @(posedge axis_clk)
if(m_axis_tlast)
$display("assertion should have passed");
else
$display("assertion should have failed");
endtask
always @(posedge clk) t();
// fork t(); // Don't bneed the fork in this case
// join_none // since the task is automatic