Understanding SystemVerilog Scheduling better

I’ve always struggled with choosing the right (not necessarily the easiest) approach for synchronizing different procedural constructs within the testbench environment. The reason for this is the lack of knowledge on the simulator scheduling for SystemVerilog. I hope answering the following cases would increase my knowledge, and hence, my confidence in choosing the right approach.

Case 1 - default clocking block

CODE

module tb;
	
  bit clk;
  always #5ns clk = ~clk;
  
  default clocking cb @(posedge clk);
  endclocking
  
  logic flag;
  always_ff @(posedge clk) begin 
    $display("always_ff exec");
  	flag <= '1;
  end

  initial begin
    ##1; // @(cb);
    $display(" ##1 executed - flag:%b", flag);
    $stop;
  end
  
endmodule

RESULT

run -all

always_ff exec

##1 executed - flag:1

** Note: $stop : testbench.sv(18)

Analysis and Questions: It seems like the code after ‘##1’ is executed after the NBA region, possibly in the observed region (?!) since using $display shows the updated value of the signal flag. Also, ‘##1’ is executed after the posedge clocking event (perhaps helps avoid race conditions (?!)). If this event gets executed in the Observed region, I had thought that there is no mechanism, within a time slot, go back to the active region. In what region is the $display command after the ‘##1’ statement executed?

Case 2 - ‘#’ delay execution vs edge execution

CODE

module tb;
	
  bit clk;
  always #5ns clk = ~clk;
  
  always_ff @(posedge clk) $display("always_ff exec");
    
  initial begin
    #5ns;
    $display(" #5ns executed");
    #0; $stop;
  end
  
endmodule

RESULT

run -all

#5ns executed

always_ff exec

** Note: $stop : testbench.sv(11)

Analysis and Questions: It seems like ‘5ns’ is executed first, even though its exactly on the time-slot where rising-edge of the clock takes place. I believe this delay event is executed in the active region (?!), and it seems to hold a higher precedence over the ‘@posedge clk’ event trigger which is also supposedly evaluated in the active region (?!). I’m not sure about how the scheduling works for this. The standard has information all over the place and I’m not fully able to relate the description there to this sort of example here.

Case 3 - covergroup sampling

CODE

module tb;
	
  bit clk;
  initial forever #5ns clk = ~clk;
  
  logic flag;
  always_ff @(clk) flag = 1;
  
  covergroup cg @(posedge clk);
    coverpoint flag {
      bins b0 = {1};
    }
  endgroup
  cg inst_cg = new();
  
  initial begin
    @(posedge clk);
    $display($get_coverage, $time);
    @(posedge clk);
    $display($get_coverage, $time);
    $stop;
  end
    
endmodule

RESULT

run -all

0 5

100 15

** Note: $stop : testbench.sv(21)

Analysis and Questions: I’m not sure when the sampling the of the covergroups happen within the schedule. I would have imagine, the ‘always_ff’ block gets executed first, and that would immediately assign the signal flag to 1. After this, the @(posedge clk) within the covergroup gets executed and that would sample the signal flag, which by now should have the value of 1. Finally, the @(posedge clk) of the ‘initial block’ is executed and then that should have displayed the 100 as the total coverage. I’m not sure what exactly is the sequence of operations here but I’m mistaken or confused to what should happen.

I’ve tried to formulate a good question. I’ll be happy to add if anything else is required.

Thanks for the time and thanks in advance for the answers.

In reply to ak180:
See my paper

It has a figure that explains the timing regions in a simple way.

IMMEDIATE ASSERTIONS AND SCHEDULED REGIONS
1800:4.4 Stratified event scheduler defines the regions within a time slot. The figure below is a graphical view of the relationship of constructs and the regions in which region they are processed. Note that these regions do iterate from the Active region to the Reactive region on an as-needed basis.

Ben Cohen
http://www.systemverilog.us/ ben@systemverilog.us
** SVA Handbook 4th Edition, 2016 ISBN 978-1518681448

  1. SVA Package: Dynamic and range delays and repeats SVA: Package for dynamic and range delays and repeats - SystemVerilog - Verification Academy
  2. Free books:
  1. Papers:
    Understanding the SVA Engine,
    Verification Horizons
    Reflections on Users’ Experiences with SVA, part 1
    Reflections on Users’ Experiences with SVA
    Reflections on Users’ Experiences with SVA, part 2
    Reflections on Users’ Experiences with SVA - Part II
    Understanding and Using Immediate Assertions
    Understanding and Using Immediate Assertions
    SUPPORT LOGIC AND THE ALWAYS PROPERTY
    http://systemverilog.us/vf/support_logic_always.pdf
    SVA Alternative for Complex Assertions
    https://verificationacademy.com/news/verification-horizons-march-2018-issue
    SVA in a UVM Class-based Environment
    https://verificationacademy.com/verification-horizons/february-2013-volume-9-issue-1/SVA-in-a-UVM-Class-based-Environment
    SVA for statistical analysis of a weighted work-conserving prioritized round-robin arbiter.
    https://verificationacademy.com/forums/coverage/sva-statistical-analysis-weighted-work-conserving-prioritized-round-robin-arbiter.
    Udemy courses by Srinivasan Venkataramanan (http://cvcblr.com/home.html)
    https://www.udemy.com/course/sva-basic/
    https://www.udemy.com/course/sv-pre-uvm/

In reply to ben@SystemVerilog.us:

Hi Ben,

Thanks for the reply. That does provide me with more intuition now and I’m now wary of scheduling iterations for assertions. I still have doubts about case 1 and 2. Not sure, how I can extrapolate that from the information you’ve provided, unless I’m missing something crucial.

In reply to ak180:
CASE 1: When multiple displays are to be provided in the same time step )e.g., 5ns) the simulator may display those outputs in any order.


module tb;
  bit clk;
  logic flag;
  always #5ns clk = ~clk; 
  default clocking cb @(posedge clk); endclocking

  always_ff @(posedge clk) begin 
    $display(" %t before flag <= 1 - flag:%b", $realtime, flag);
    $display("%t always_ff exec", $realtime);
  	flag <= '1;
    $display(" %t after fleag<=1 - flag:%b", $realtime, flag);
  end
 
  initial begin
    $display(" %t At initial - flag:%b", $realtime, flag);
    ##1; // @(cb);
    $display(" %t ##1 executed - flag:%b", $realtime, flag);
    $stop;
  end
endmodule

run -all
#                     0 At initial - flag:x
#                     5 before flag <= 1 - flag:x  // in the always
#                    5 always_ff exec              // in the always  
#                     5 after fleag<=1 - flag:x    // X because we're in the ACTIVE region 
#                     5 ##1 executed - flag:1      // in the initial, 
                      // in the time step after the ##1, the <=1 is updated 
# ** Note: $stop    : testbench.sv(18)
#    Time: 5 ns  Iteration: 2  Instance: /tb
# Break at testbench.sv line 18

Ben