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:
- Why does
always @(posedge composite)
fire whencomposite
is (and remains) zero? - How can I achieve the behavior shown by
desired
without resorting to such haphazard techniques as decrementing the counter on the falling edge of thedecode
signal?
2 Answers 2
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.
-
\$\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, andclk
instantly becomes 1, socomposite
never goes high. Unless the race condition happens within iVerilog itself? As for usingdecode
as an enable signal andclk
as a clock, isn't that the approach I took withdelayed_counter
? \$\endgroup\$ecapstone– ecapstone2020年08月14日 02:26:38 +00:00Commented 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 whendecode
initially goes high. Fix your race conditions and your design will be much better behaved. \$\endgroup\$The Photon– The Photon2020年08月14日 02:31:04 +00:00Commented Aug 14, 2020 at 2:31 -
\$\begingroup\$
decode
andclk
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– ecapstone2020年08月14日 02:36:01 +00:00Commented 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– The Photon2020年08月14日 02:38:38 +00:00Commented 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– ecapstone2020年08月14日 02:42:46 +00:00Commented Aug 14, 2020 at 2:42
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.