Understanding @(posedge) in Verilog

verilog

In the circuit below, I'm trying to count the number of clock pulses that happen while the decode signal is high. In order to do this, I create a composite wire that takes the AND of clk and decode, and increment a counter at the positive edges of this signal.

module countPulses(clk, decode);
  input clk;
  input decode;

  wire composite = clk & decode;
  
  reg  [15:0] composite_counter = 16'h0000;  // Increments too often
  reg  [15:0] delayed_counter   = 16'h0000;  // Lags 1 cycle behind desired
  reg  [15:0] desired           = 16'h0001;  // Intended counter behavior

  always @(posedge composite)
  begin
    composite_counter <= composite_counter + 1;
    desired <= desired + 1;
  end

  // Manually fix up the desired results on the falling edge of `decode`
  always @(negedge decode)
    desired <= desired - 1;

  always @(posedge clk)
    if (decode) delayed_counter <= delayed_counter + 1;

endmodule

Unfortunately, composite_counter doesn't work as I expected. I'm looking for the values shown in desired, but instead, composite_counter increments again at the falling edge of the decode signal. I don't understand why this happens, as you can see in the trace that when this occurs, composite and decode are both zero. There should be no overlap between the rising edge of clk and the falling edge of decode, but for some reason, it's being treated as a posedge anyways. I'm new to Verilog and hardware design, so perhaps I'm misunderstanding how @ posedge works.

I also tried incrementing a counter (delayed_counter) at posedge clk instead of posedge composite and checking if decode is high. This doesn't exhibit the double-counting behavior that composite_counter does, but the values are delayed one cycle from those in desired. I understand why this is happening, but wanted to point it out as a potential solution that won't work.

GtkWave traces showing undesired behavior

With that, my two questions are:

  1. Why does always @(posedge composite) fire when composite is (and remains) zero?
  2. How can I achieve the behavior shown by desired without resorting to such haphazard techniques as decrementing the counter on the falling edge of the decode signal?

Best Answer

You have a race condition between the falling edge of decode and the rising edge of clock.

Zoom in your wave viewer and you’ll probably see composite going high very briefly at that edge.

To fix it, make sure that decode goes low some nonzero time before clock goes high. Or, even better, instead of using a gated clock (google this term if you don’t know it), use decode as an enable signal, and clock as a clock.