System verilog simulation performance for uvm_hdl_read vs assign statement

1.4k Views Asked by At

I need to generate around 10,000 connectivity assertions to check that values driven at DUT interface at the beginning of simulation has reached (and is retained) at around 10,000 points inside the DUT throughout the simulation. The 10k destination points inside DUT are available through xls, hence, if I can take the paths to an array, I could write a single assertion property and instantiate it multiple times while iterating through the array. What is the better approach here for simulation performance?

  1. Using assign :
logic[7:0] dest_vals[10000];
assign dest_vals[0] = dut_path0.sig0; //This assignment code can be script-generated 
assign dest_vals[1] = dut_path1.sig1;
....
assign dest_vals[9999] = dut_path9999.sig9999;

property check_val(expected_val, dut_val);
 @(posedge assert_clk) expected_val == dut_val; 
endproperty

genvar i;
generate
for(i=0;i<9999;i++)
 assert property check_val(exp_val[i], dest_vals[i]);
endgenerate
  1. Using uvm_hdl_read :
string dest_val_path[10000] = '{
"dut_path0.sig0",
"dut_path1.sig1",
....
"dut_path9999.sig9999"
};

property check_val(expected_val, dut_val);
 @(posedge assert_clk) expected_val == dut_val; 
endproperty

genvar i;
generate
for(i=0;i<9999;i++) begin

 initial forever begin
  @(posedge assert_clk);
  uvm_hdl_read(dest_val_path[i],dest_vals[i]);
 end

 assert property check_val(exp_val[i], dest_vals[i]);

end
endgenerate


Follow up question: Is there a way to change static array of size 10k to dynamic array/associative array/queue, so that if 10k destination points changes to 11k in future, array need not be re-sized manually?

1

There are 1 best solutions below

1
On BEST ANSWER

Using uvm_hdl_read to access a signal by a string name is significantly slower than a direct hierarchical reference to a signal in an assign statement. A lot of code gets executed to lookup up that signal name in a string database and retrieve it from the simulator's internal database using the SystemVerilog's C based "VPI" routines. Plus, you can lose some optimizations because the value of the signal needs to be readily available at any point in time. In the case of the continuous assign statement, the simulator can work backwards and figure out it only needs the signal value on the assert_clk trigger.

How noticeable this performance difference is depends on a number of other factors

  1. The overall size of the entire design's activity relative to additional code executed by uvm_hdl_read
  2. How often the assert_clk triggers relative to the other activity in the design
  3. How good a job you were able to limit VPI access to just the signals involved. Every signal you give VPI access to increases the size of the string database and prevents optimizations around that signal.

There is another option that does not involve assign statements or generate loops. You can use the bind construct to insert a module with your assertion. This works particularly well in your situation since you already have a script that produces the code for you.

module #(type T=logic [7:0]) mcheck(input logic clk, T expected_val, dut_val);
  property check_val;
   @(posedge clk) expected_val == dut_val; 
  endproperty
  assert property(check_val);
endmodule 

bind dut_path0 mcheck m(tb_path.assert_clk,tb_path.expected_val[0], sig0);
bind dut_path1 mcheck m(tb_path.assert_clk,tb_path.expected_val[1], sig1);
...

Note the port connections in the bind module are relative to the dut_path where mcheck is bound into.