Glitch issue , How to solve it?

Hi,

I am trying to count how many times some condition occurs, I used “pulse_done” variable to detect the condition and “pulse_done_cnt” to count that pulse.
Variable “pulse_done” asserts for 3 times, however “pulse_done_cnt” shows count as 5.
I think there is glitch happening in between due to which it counts extra pulses.
Could you please help me to solve this issue.


module glitch_counter;

  logic a, b, pulse_done;
  logic clk=0;
  logic [2:0] data;
  reg a_reg, b_reg;
  logic [2:0] data_reg;
  int pulse_done_cnt;

  assign a = a_reg;
  assign b = b_reg;
  assign data = data_reg;

  assign pulse_done = a && b && data == 'h5;

  always@(posedge pulse_done) begin
      pulse_done_cnt += 1;
  end
  
  initial begin
      $monitor("@%0t: pulse_done_cnt=%0d, pulse_done=%0d",$realtime,pulse_done_cnt,pulse_done);
      $dumpfile("glitch_counter.fsdb");
      $dumpvars(0,glitch_counter);
  end

  initial begin
      #100;
      $finish;
  end

  initial begin
      fork
          forever begin
              #1;
              clk <= ~clk;
          end
      join_none

      a_reg = 0;
      b_reg = 1;
      data_reg = 0;
      #5;
      fork
          begin  //a_reg
              int delay;
              forever begin
                  delay = $urandom_range(4,7);
                  a_reg <= 1;
                  @(posedge clk);
                  a_reg <= 0;
                  repeat(delay) @(posedge clk);
              end
          end

          begin
              int i=0;
              forever@(posedge a_reg) begin
                  i = i+1;
                  if (i%2 == 0) begin
                      data_reg <= 5;
                  end else begin
                      data_reg <= 1;
                  end
              end
          end

      join_none
  end

endmodule 

I tried this code and it is working, Is it the best solution or is there anything better than this one?


  //always@(posedge pulse_done) begin
  always@(negedge clk) begin
      if(pulse_done)
          pulse_done_cnt <= pulse_done_cnt + 1;
  end

In reply to hvalec:

I’m not sure what kind of better solution you’re looking for.

Your code has a delta cycle glitch. a_reg and data_reg are being updated in two different active event regions. Your solution samples pulse_done so it ignores the glitch it has. Note that $monitor or VCD $dumpvars do not show glitches.

In reply to dave_59:
Thanks for the reply Dave.
Rather ‘better’ I should have used ‘alternate’, could we use “uvm_wait_for_nba_region” somehow such that assign statement samples values in NBA region to avoid that glitch?

Second thing is, I am not sure how glitch is generated in the first place itself? Since I am driving a_reg and data_reg in the NBA region and trying to sample in the next active region i.e driving and sampling are in different timing region then how did glitch is generated? (referring to the time when pulse_done_cnt is going 1->2 due to glitch)

Thanks.

In reply to hvalec:

You are making assignments to a_reg and data_reg in successive NBA regions because you are using different posedge events. Remember that each event region may create events in other regions and will keep looping back to earlier regions until they are empty of events.

Your first forever loop waits for @(posedge clk) in the Active region and schedules assignments to a_reg in an NBA region. After the Active region is empty, we advance to the NBA region where the update to a_reg happens. That schedules the @(posedge a_reg) to resume in the Active region, as well as scheduling the continuous assign statements to revaluate.

Once the NBA region is empty, we go back to the Active region and evaluate the assign statements, update their values and if there is a posedge of a_reg, resume that process. That schedules assignments to data_reg in the NBA region. After the Active region is empty, we advance to another NBA region where the update to data_reg happens. That schedules the continuous assign statements to revaluate for the second time in another Active region. It is between these two evaluations where the glitch happens.

To avoid glitchy behavior, I suggestion only using @(posedge/negedge clk) and no other edges of any other signals. Instead of

@(posedge a_reg)

use

@(posedge clk iff a_reg)

In reply to dave_59:

Remember that each event region may create events in other regions and will keep looping back to earlier regions until they are empty of events.

Understood now, Thanks Dave for the detailed explanation.