4
\$\begingroup\$

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
\$\endgroup\$
6
  • 1
    \$\begingroup\$ 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 \$\endgroup\$
    – BoredBsee
    Mar 15 '21 at 23:03
  • \$\begingroup\$ 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. \$\endgroup\$
    – BoredBsee
    Mar 15 '21 at 23:06
  • \$\begingroup\$ Don’t you get warnings or errors? \$\endgroup\$
    – Michael
    Mar 16 '21 at 6:31
  • \$\begingroup\$ 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. \$\endgroup\$
    – BoredBsee
    Mar 16 '21 at 17:55
  • \$\begingroup\$ 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). \$\endgroup\$
    – Michael
    Mar 16 '21 at 18:08
9
\$\begingroup\$

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

\$\endgroup\$
4
\$\begingroup\$

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
  else begin // synchronous add
    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.

\$\endgroup\$
0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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