Time0 signal checker

Hi folks,

I am trying to understand how the time0 events such as clk, reset, are scheduled in system verilog, and come up with 2 questions(I hope it is not TOOL related questions):

  1. At simulation time0, why does posedge clk get triggered/scheduled if clk is initialized to 1? Specifically, it should NO posedge clk when clk initialize to 1, and rstn default to 0. According to Clifford’s SNUG2006 doc, it should be NO time0 event for this case? Same way for rstn, it should not trigger always @(posedge clk or negedge rstn).

  2. At simulation time0, en_checker detects EN=x because en is updated in NBA region which is after inactive region(#0). I wonder if there is a way to fix the problem(EN is not unknown) by only changing clk, rstn in tb module and keeping the rest 2 modules(en_checker, dut) same.

module en_checker(EN);
   input EN;
   //#0, inactive region
   initial #0 if ( EN !== 1'b0 &&  EN !== 1'b1) $display ("%m, ***FATAL***: EN is NOT connected!");
endmodule

module dut(input clk, resetn);
   reg    en;

   always @(posedge clk or negedge resetn) begin
      if (~resetn) begin
         //en is updated in NBA region
         en <= 1'd1;
      end // end if (~resetn)
   end // always @ (posedge clk or negedge resetn)

   en_checker m_checker(.EN(en));
endmodule


module tb;
   
   bit clk;
   bit rstn;

   dut dutI(.clk(clk), .resetn(rstn));
   
   always #1 clk = ~clk;
   
   initial begin
      //active region blocking assignment
      clk = 1;
      #10 $finish;
   end

   //display dutI.en value in active region
   initial $display("en: %0b", dutI.en);

   initial begin
      $dumpfile("tb.vcd");
      $dumpvars(0, tb);
   end

endmodule

https://drive.google.com/drive/folders/1ejQV9sNezummVn5V7FovucU3x7Thp5yN?usp=sharing

In reply to mlsxdx:

I tried to fix it by using the below in tb
initial $deposit(dutI.en, 0);

It works. Any other ways to fix by modifying clk, reset?

In reply to mlsxdx:

You get a posedge clk at time 0 because its default initial value is 0, and you set it to 1 at time 0. Either remove your
clk = 0;
procedural assignment at time 0, or declare it with an initial value of 1.

bit clk = 1;

That initialization happens before any other initial or always processes start. You can do the same thing with en. I am not exactly sure what you are trying to check.

In reply to dave_59:

In reply to mlsxdx:
You get a posedge clk at time 0 because its default initial value is 0, and you set it to 1 at time 0. Either remove your
clk = 0;
procedural assignment at time 0, or declare it with an initial value of 1.

bit clk = 1;

That initialization happens before any other initial or always processes start. You can do the same thing with en. I am not exactly sure what you are trying to check.

Thank you for your reply, Dave.
Why changing to bit clk = 1, a posedge clk is still there because dutI.en is 1 in the waveform. That basically means always @(posedge clk or negedge resetn) get executed at time0. Can you help me to understand what the magic is there on always statement on time0?

In reply to dave_59:

In reply to mlsxdx:
You get a posedge clk at time 0 because its default initial value is 0, and you set it to 1 at time 0. Either remove your
clk = 0;
procedural assignment at time 0, or declare it with an initial value of 1.

bit clk = 1;

That initialization happens before any other initial or always processes start. You can do the same thing with en. I am not exactly sure what you are trying to check.

The checker is from a third-party module, that I assume there may be a reason to put there.

In order to make the checker not fail, I am trying to see if there is a way to play with tb signals - clk, reset to get dut module output - en updating before inactive region(the checking en occurring in inactive region).

en is updating in NBA region(which is after inactive region), the initial #0 check it while en is still x(reg type initial value). Is my understanding correct?

Then I am getting confused on time0, why en is reset to 1 from the waveform even bit clk = 1?

In reply to mlsxdx:
Sorry to mislead you, but I just realized your module dut has input ports clk and resetn which are wires starting out as unknown values. You have the wire resetn connected to the bit rstn. That creates a negedge resetn at time 0 regardless of what happens to clk.

Your testbench can make procedural assignment directly to en to make the checker not fail.

initial begin
      //active region blocking assignment
      dutI.en = 0;
      #10 $finish;
   end

If en happens to be a wire and not a variable, you can use a force statement followed by a release.

In reply to dave_59:

Not misleading at all. I think you comments are the only source to allow me get better understanding for this specific problem in present. :p

From your latest reply, does that mean the clk, reset in each module(dutI) is not same time event as the ones in tb module? If yes, then in what time region are each instantiation module’s input ports eval & update?

In reply to mlsxdx:

There is an implicit continuous assignment between the variables in your testbench, and the nets in your DUT because of the connections made in the dut instance. This all happens within the active event region.