0
\$\begingroup\$

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?
\$\endgroup\$

2 Answers 2

1
\$\begingroup\$

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.

\$\endgroup\$
6
  • \$\begingroup\$ Sorry, I should have been more clear about this, but when I said "There should be no overlap" I meant that I stepped through at the timescale of the simulation and confirmed that there was no overlap. At the 1500ns mark, decode instantly becomes 0, and clk instantly becomes 1, so composite never goes high. Unless the race condition happens within iVerilog itself? As for using decode as an enable signal and clk as a clock, isn't that the approach I took with delayed_counter? \$\endgroup\$
    – ecapstone
    Commented Aug 14, 2020 at 2:26
  • 1
    \$\begingroup\$ @ecaostone yes, delayed_counter uses the correct approach. The only reason that counter is delayed is because, again, you have a race condition when decode initially goes high. Fix your race conditions and your design will be much better behaved. \$\endgroup\$
    – The Photon
    Commented Aug 14, 2020 at 2:31
  • \$\begingroup\$ decode and clk are both produced outside of my design, but I'll investigate them a bit more and (hopefully) mark this as the accepted answer. Thanks! \$\endgroup\$
    – ecapstone
    Commented Aug 14, 2020 at 2:36
  • \$\begingroup\$ If this is fpga work, you can likely use clock manage mental resources to delay the clock signal by a fraction of a period where it enters the chip. Or use its negative edge instead of positive within your design. \$\endgroup\$
    – The Photon
    Commented Aug 14, 2020 at 2:38
  • \$\begingroup\$ Oddly enough, this design will only ever run in a simulator, so while the usual hardware constraints don't apply, clever tricks like that aren't an option. \$\endgroup\$
    – ecapstone
    Commented Aug 14, 2020 at 2:42
0
\$\begingroup\$

The delayed_counter is the normal way I used to count when decode is high.

In your waveform, delayed_counter increments at 1500ns, this really means that clk edge "sees" a high decode. This can explain why composite_counter increments again at that time: there's a glitch on composite. You're doing functional simulation with zero delay, so we are hardly to tell the order of 2 events if they happen at the exactly same time. Even though the edge of clk and decode aligns, the internal event scheduler of your simulater places the event of "decode rises" before the event of "clk rises". There's something to do with the way you produce these 2 signals in your testbench.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.