1
votes

Could someone explain to me why a latch would be inferred instead of a flip-flop?

always_ff @ (posedge clk, negedge rst) 
begin
  if (!rst)
    a <= '0;
end

Shouldn't the fact that the always block is sensitive to a signal edge be enough to infer a flip-flop. In this case when a negative edge of reset is triggered a gets 0, else it keeps former value.

This question comes from the selected best answer from this stackoverflow question:
System Verilog always_latch vs. always_ff

===========================================================================

I will share here what I found out so far. The reason why this synthesizes to a latch, instead of a flip-flop is because on the right side of the assignment is a CONSTANT. When this is the case the behavior of a latch and a flip-flop are EQUIVALENT, because it does not matter whether it catches the input value on a signal edge (flip-flop) or while input latching is enabled (latch) as the input does not change. So the synthesis tool chooses the element that takes less resources, i.e. the latch.

On the other hand, if on the right side of the assignment there was a VARIABLE, the synthesis would have to infer a flip-flop, because it would matter whether the input is sampled on an edge (flip-flop) or during input latching is enabled (latch), meaning the two logic elements are NOT EQUIVALENT.

Here is an example. First two always blocks will synthesize to a latch (in Quartus 14), which is OK, as they are equivalent, because of a constant. But, the 3. and the 4. always block will also be synthesized into a latch, which is not the intended behavior and these blocks are not equivalent! The 3. block will give a warning, while the 4. one won't.

 module ff_latch(
   input logic clk,
   input logic nrst,
   input logic a,
   output logic t, x, y, z
 );

    always_ff @(posedge clk, negedge nrst) 
       begin
          if (!nrst)
           t <= 0;
       end

    always_latch
       begin
          if (!nrst)
           x <= 0;
       end

    always_ff @(posedge clk, negedge nrst) 
       begin
          if (!nrst)
           y <= a;
       end

    always_latch
       begin
          if (!nrst)
           z <= a;
       end

endmodule: ff_latch

To me this behavior is not correct, as I specifically said I want a flip-flop (with edge triggering). It's not even that the coding is ambiguous, always blocks 3. and 4. are clearly different, as can be seen in this waveform from the above simulation:

enter image description here

Block 3. (tb_y) behaves like a asynchronous flip-flop and block 4. (tb_z) behaves like a latch. But the synthesis tool infers a latch in both cases.

If someone can shed some light on this or comment the code or the waveform, it would be much appreciated.

2

2 Answers

4
votes

A synthesiser will infer a latch because this code behaves like a latch. It does not behave like a flip-flop. It's as simple as that.

Think about how this code behaves: initially the value of a will be 'x. When rst is asserted low then a will become '0. a will then remain at '0 forever. The state of a therefore depends not only on the current state of the inputs, but also on the past state. Therefore, we have sequential logic, not combinational logic. Flip-flops change state on a clock edge; a does not. The fact that the always block is sensitive to a signal edge is irrelevant. This just means that the code inside is executed on that signal edge - the positive edge of clk. But when that occurs, nothing happens, so this code behaves like a latch.

1
votes

Because you haven't specified what happens at posedge of the clock. It is as if a does not depend on clk or its posedge at all. All your description says is that a is set to 0 when rst=0. Moreover, it says (implicitly) that a keeps its previous value in all other cases. This can be implemented by a latch.

Notice that just because you have @posedge of clk does not mean every variable inside that block will be synthesized as a flop. You also need a non-blocking assignment to a when the block is activated at posedge of clk. See here.

If you insist on having a flop to implement the same functionality, you can try this:

always_ff @ (posedge clk or negedge rst) 
begin
  if (!rst)
    a <= '0;
  else 
    a <= a;  //Here, we are specifying what happens @posedge of clk
end