可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
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:
- use a
default
case OR
- use default assignments OR
- 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