I tried to figure out the inferred latch and why it is needed internally, but I couldn't find any resources with enough detail.
A latch is inferred within a combinatorial block where the net is not assigned to a known value. Assign a net to itself will still infer a latch. Latches can also be inferred by missing signals form a sensitivity list and feedback loops.
The proper way of inferring a intended latch in Verilog/SystemVerilog are:
/* Verilog */ //// /* SystemVerilog */
always @* //// always_latch
begin //// begin
if (en) q = d; //// if (en) q = d;
end //// end
Signal(s) missing for the sensitivity list (this is why @*
should be used):
always @(a or b) // inferred latch :: "c" missing for the sensitivity list.
begin
out = a + b + c;
end
Missing Condition:
always @*
begin
case(in[1:0])
2'b00: out = 1'b0;
2'b01: out = 1'b1;
2'b10: out = 1'b1;
// inferred latch "out" :: missing condition 2'b11/default
endcase
end
always @*
begin
next0 = flop0;
next1 = flop1;
// inferred latch "next2" :: missing initial condition
next3 = flop3;
case(a[2:0])
3'b001: next0 = in;
3'b010: if(b) next1 = in;
3'b100: if(c) next2 = in;
default: if(!b&&!c) next3 = in;
endcase
end
Feedback Loop:
assign out = en ? in : out; // inferred latch "out" :: feedback to mux
assign a = en ? z : c;
// ... any amount of code between ...
assign z = en ? a : y; // inferred latch "a" :: feedback chain
always_latch
.always @*
or SystemVerilog's always_comb
.case
statements should have a default
condition.if
statements should have a corresponding else
.case
or if
).always_comb
can help identify inferred latches with linting and logical-equivalency-checking tools.Worst case scenario, put all logic inside synchronous blocks. All inferred latches become inferred flip-flops. This is usually a bad idea because it can unnecessarily increases the gate count, create more routing, and impact timing.