-->

Why does an If statement cause a latch in verilog?

2019-07-02 03:10发布

问题:

I am trying to code a controller/data-path implementation in Verilog, and I am confused on what will cause an unwanted latch. Essentially, I have a state machine updating on the negedge clock. This state machine sends 5 control signals (loadSquare, loadDelta, addDelta, etc.) to the data-path based on what state the machine is in. The code for the data-path and controller is shown below.

Data-path

//Control lines
reg addSquare, addDelta, decDelta;
reg loadSquare, loadDelta;

//Input lines
reg [8:0] square, delta;

//Output register
reg [7:0] outReg;

always @(posedge clk) begin
  if (loadSquare)
     square = 9'h1;  //used on initialization

  if (loadDelta)
     delta = 9'h3;   //used on initialization

  if (addSquare)
     square = square + delta; 

  if (addDelta)
     delta = delta + 2'h2;

  if (decDelta)
     outReg = (delta>>1) - 1;  //used for output
  else
     outReg = Input;
end

Controller

//Output of module
assign Output = outReg;

//Finite State Machine
always @(currentState) begin
    case(currentState)
        2'h0:   begin       //initialize values, wait for start
        {loadSquare, loadDelta} = 2'b11;
        {addSquare, addDelta, decDelta} = 3'h0;
     end
        2'h1: begin
        {loadSquare, loadDelta} = 2'b00;
        {addSquare, addDelta, decDelta} = 3'b110;  //add square and delta
     end
        2'h2: begin
        {loadSquare, loadDelta} = 2'b00;
        {addSquare, addDelta, decDelta} = 3'b001;  //decrement delta, wait for reset
     end
        default: ; // unused
    endcase

//Next state logic implemented on negedge clk (not shown)

This code generates the following warnings in Xilinx:

WARNING:Xst:737 - Found 1-bit latch for signal <addDelta>. Latches may be generated from incomplete case or if statements. We do not recommend the use of latches in FPGA/CPLD designs, as they may lead to timing problems.
WARNING:Xst:737 - Found 1-bit latch for signal <decDelta>. Latches may be generated from incomplete case or if statements. We do not recommend the use of latches in FPGA/CPLD designs, as they may lead to timing problems.
WARNING:Xst:737 - Found 1-bit latch for signal <loadDelta>. Latches may be generated from incomplete case or if statements. We do not recommend the use of latches in FPGA/CPLD designs, as they may lead to timing problems.
WARNING:Xst:1294 - Latch <loadDelta> is equivalent to a wire in block <ModuleName>.
WARNING:Xst:1294 - Latch <decDelta> is equivalent to a wire in block <ModuleName>.
WARNING:Xst:1294 - Latch <addDelta> is equivalent to a wire in block <ModuleName>.

I understand that incomplete if statements cause latches. In order to try to account for this, I have tried 2 different implementations but they do not remove the warnings. I am especially confused for the "decDelta" case because I don't understand what I am not accounting for in this conditional statement.

Try #1

always @(posedge clk) begin
  if (loadSquare)
     square = 9'h1;
  else
     square = square;

  if (loadDelta)
     delta = 9'h3;
  else
     delta = delta;

  //... and so on

Try #2

always @(posedge clk) begin
  square = square;
  delta = delta;

  if (loadSquare)
     square = 9'h1;

  if (loadDelta)
     delta = 9'h3;

  //... and so on

The code works as expected when I run a simulation, but I wanted to learn a little more about what causes these warnings.

回答1:

A latch is a basic memory element, it is open or closed ie it is level sensitive. A flip-flop is basically two latches with one operating on the invert of the enable signal, this makes it edge sensitive.

When using always @(posedge clk) you have implied a flip-flop that loads data values on the rising edge of clk. Latches do not get implied inside this process (always @(posedge clk)).

As Sharvil111 has described latches are implied when you have left undefined states in combinatorial sections ie always @* processes. If some thing is undefined in part of a conditional then it retains its value. Value retention is state, and since combinatorial sections are not edge sensitive you have forced the tool to insert a latch.

To avoid this fully define the conditional output:

always @(currentState) begin
case(currentState)
    2'h0:   begin       //initialize values, wait for start
    {loadSquare, loadDelta} = 2'b11;
    {addSquare, addDelta, decDelta} = 3'h0;
 end
    2'h1: begin
    {loadSquare, loadDelta} = 2'b00;
    {addSquare, addDelta, decDelta} = 3'b110;  //add square and delta
 end
    2'h2: begin
    {loadSquare, loadDelta} = 2'b00;
    {addSquare, addDelta, decDelta} = 3'b001;  //decrement delta, wait for reset
 end
    default: begin
    {loadSquare, loadDelta} = 2'b00;
    {addSquare, addDelta, decDelta} = 3'b000;
    end
endcase


回答2:

Latches are inferred when a variable will have to retain its previous value, if it is not assigned a value in an always block. A latch must be created to store this present value.

Latches can cause various race conditions. Unwanted latches create a feedback in a combinational circuit, i.e. it routes the output back to the input - which can be unpredictable causing unstable circuit behavior.

An incomplete if-else statement will generate unwanted latches. An if-else statement is considered "incomplete" if the one of the condition is not defined for all possible input conditions. Similarly, an incomplete case statement, that does not have a default statement can also infer to latch.

A complete if-else statement refers to the following Mux:

While and incomplete if-else refers to a feedback path from output to input, in order to hold the previous value. Similar applies to case statement.

As a rule, combinational loops must be avoided:

A general intention of a combinational circuit is that the output is a function of input only and the circuit should not contain any internal state (i.e., memory).

As a contradiction, verilog standard specifies that a variable must retain/hold its previous value if it is not assigned a value in an always block. This is the root cause of latch creation.

To avoid the latches, following points must be kept in mind:

  • Include all the branches of an if or case statement.
  • Assign a value to every output signal in every branch.

Here, to avoid latch creation, either you can else branch and explicitly assign all output variables, such that other input is grounded.

if (loadSquare)
     square <= 9'h1;  //used on initialization
else
     square <= 9'h0;  // similar for all the variables

Another alternative is to assign a default value at every clock tick.

always @ (posedge clk)
begin
square <= 9'h0;    // similar for all the variables
if (loadSquare)
     square <= 9'h1;  //used on initialization
end

Side Note : I've used non-blocking assignments statements here, for proper flip-flop synthesis.

For detailed synthesis information, refer to FPGA prototyping by Verilog examples by Pong P. Chu pdf. Also, this and this links about latch creation may be useful.

Image courtesy doulous.com.



回答3:

The latches are cause by the state machine logic. The following always block is sensitive to currentState and not to a clock. This is not bad, but needs some extra precautions to hinder latch creation:

  1. use a default case OR
  2. use default assignments OR
  3. use a different FSM pattern

Here is your code with my additions using default assignments:

//Finite State Machine
always @(currentState) begin
    // default assignments
    {loadSquare, loadDelta} = 2'b0;
    {addSquare, addDelta, decDelta} = 3'h0;        

    case(currentState)
      2'h0:   begin       //initialize values, wait for start
        {loadSquare, loadDelta} = 2'b11;
        {addSquare, addDelta, decDelta} = 3'h0;
      end
      2'h1: begin
        {loadSquare, loadDelta} = 2'b00;
        {addSquare, addDelta, decDelta} = 3'b110;  //add square and delta
      end
      2'h2: begin
        {loadSquare, loadDelta} = 2'b00;
        {addSquare, addDelta, decDelta} = 3'b001;  //decrement delta, wait for reset
      end
      default: ; // unused
    endcase

//Next state logic implemented on negedge clk (not shown)

For further information on latch creation have a look at @sharvil111's answer. He addresses this topic in a more general way.



回答4:

A latch is inferred when a variable within a combinational block is not assigned a value within all possible permutation of the blocks functionality.

case(currentState)
2'h0:   begin       //initialize values, wait for start
  {loadSquare, loadDelta} = 2'b11;
  {addSquare, addDelta, decDelta} = 3'h0;
end
2'h1: begin
  {loadSquare, loadDelta} = 2'b00;
  {addSquare, addDelta, decDelta} = 3'b110;  //add square and delta
end
2'h2: begin
  {loadSquare, loadDelta} = 2'b00;
  {addSquare, addDelta, decDelta} = 3'b001;  //decrement delta, wait for reset
end
default:  ; // unused // <-- not assigned so assumed keep; inferred latches
endcase
...

Doing something like addSquare = addSquare; is still an inferred latch. addSquare (and all the other variables) needs to be assigned to a constant, a flop (edge sensitive flip-flop), or combinational function terms of constants and flop values.

If you truly do not need addSquare (and all the other variables), then just assign them to a constant in the default condition.

If you do need to keep the value, then you need to add a flop that is synchrously assigned to the variable. In the default condition, the variable needs to be assigned to the flop. Example:

always @(posedge clk) begin
  ...
  addSquare_keep <= addSquare;
  ...
end
always @* begin
  ...
  case(currentState)
  ...
  default : begin
    ...
    addSquare = addSquare_keep;
    ...
  end
  endcase
  ...
end