# Verilog odd behavior with multiple edge detect

So I'm a newbie to Verilog. I decided to purchase a nice board (a Terasic DE0-CV) and teach myself some Verilog. And I'm seeing some strange behavior that I can't explain.

I lifted some code out of an example that drives the 7-seg LEDs. And I have them tied to a register. Whatever the register holds, the LEDs display.

reg [23:0]  mSEG7_DIG;
SEG7_LUT_6          u0  (   .oSEG0(HEX0),
.oSEG1(HEX1),
.oSEG2(HEX2),
.oSEG3(HEX3),
.oSEG4(HEX4),
.oSEG5(HEX5),
.iDIG(mSEG7_DIG) );


I made a simple counter to drive the register, like this:

always @(negedge KEY[3]) begin
mSEG7_DIG <= mSEG7_DIG + 1;
end


And that works just fine. Click Key[3] on the board, the counter counts up from zero with each key click. Works like a charm. Sees the edge, increments the register, displays on the LEDs. So next, I wanted to make a way to clear the register to start back from zero. This is the idea I was thinking of.

always @(negedge KEY[3]) begin
mSEG7_DIG <= mSEG7_DIG + 1;
end

always @(negedge KEY[2]) begin
mSEG7_DIG <= 0;
end


This turns out to not be legal, since I have two always blocks trying to drive the same register. But you get where I'm going with this.

So I figure "Ok, I'll make them into one always block, then check the switch levels to see what we're trying to do, increment or clear."

So I did this to start.

always @(negedge KEY[3], negedge KEY[2]) begin
mSEG7_DIG <= mSEG7_DIG + 1;
end


For whatever reason when I do this, the counter counts so fast you can't see it. I've tested it for hardware problems by doing this:

always @(negedge KEY[2]) begin
mSEG7_DIG <= mSEG7_DIG + 1;
end


And that works fine too.

So what am I missing? Why does having two edge dependent signals in my always block's dependency list make it seem to be always true?

Edit: The hint from IanJ - "the synthesis tool doesn't want to make something sensitive to two different edges", and being able to see what synthesis is doing with my code in RTL viewer - this allowed me to solve the problem.

The problem - imagine a CLK line going into a D type flip flop. And you want two signals to control it. But I didn't specify HOW. The synthesis tool would have to be a mind reader to understand my intention. You have to explicitly say how you're triggering. This solves the problem. Full points to IanJ for the tip - that led to this solution.

wire change;

assign change = ~KEY[2] | ~KEY[3];

always @(posedge change) begin
if(~KEY[2]) begin
mSEG7_DIG <= mSEG7_DIG + 1;
end
else begin
mSEG7_DIG <= 0;
end
end

• I just learned about the RTL viewer in Quartus! You can see in the second image how - for whatever reason - the synthesis tool looks at the "two clocks" and says "nah!" and removes the register. I wonder why it thinks that's a good idea? Seems to me like having a dependence on two edge sensitive inputs wouldn't do this. imgur.com/a/gDpPaJI Mar 15, 2021 at 23:03
• Oh, and please ignore the AND gate in that image, that's experiment #1 where I'm just using 2 of the KEYS[] buttons to drive a single LED. Basically my "hello world" program to prove the tools are working. Mar 15, 2021 at 23:06
• Don’t you get warnings or errors? Mar 16, 2021 at 6:31
• I get a warning, "Warning (332060): Node: KEY[2] was determined to be a clock but was found without an associated clock assignment.", but nothing to indicate that they're removing the entire D type flip flop register. I'm learning that synthesis is a far different animal than simulation. Just because it's legal in the language doesn't mean that you can synthesize it. Mar 16, 2021 at 17:55
• Well, if it’s not defined/assigned as a clock, what is the synthesis tool supposed to do? In digital design you should always have a pretty clear idea what kind of circuit you want (and what you are going to get). Mar 16, 2021 at 18:08

Learning Verilog is one thing. It also good to learn digital design. Modern designs use clocks. The synthesis tool doesn't want to make something sensitive to two different edges.

You should us a clock and either count or reset depending on the input. You should digitally detect the edge to count up.


always @(posedge clock) begin
KEY3_d1 <= KEY[3];
if (!KEY3_d1 && KEY[3]) begin
mSEG7_DIG <= mSEG7_DIG + 1;
else if (KEY[2]) then
mSEG7_DIG <= 0;
end
end



Assuming:

• KEY input is already de-bounced
• Your board has flip-flops with asynchronous set/reset
• No other edge events will be added

Then you could do this:

always @(negedge KEY[3], negedge KEY[2]) begin
if (!KEY[2]) begin // async reset
mSEG7_DIG <= 0;
end
mSEG7_DIG <= mSEG7_DIG + 1;
end
end


However the preferred solution is to run off a common clock. You can detect level change in the inputs by comparing its current value verses its value from last clock.

always @(posedge clock) begin
prev_KEY_3_ <= KEY[3];
if (!KEY[2]) begin
mSEG7_DIG <= 0;
end
else if (!KEY[3] && prev_KEY_3_) begin // <-- fall detector
mSEG7_DIG <= mSEG7_DIG + 1;
end
end


I recommend running simulation before loading into an FPGA. With simulation you have the option of viewing the waveform for all signals which is critical for debugging complicated designs.