Search code examples
verilogfpgaxilinx

Why does an If statement cause a latch in verilog?


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.


Solution

  • 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