Accidental Latches
The last article was about accidental storage in the simulation. This one is about accidental storage in the netlist, which a perfect @(*) does nothing to prevent, because it comes from the body of the block. Leave a path through a combinational block on which an output is not assigned, and the synthesiser, faithfully, builds a latch to hold it.
A latch is the level-sensitive element of section 3.1: transparent while its enable is active, frozen when it is not. An unintended one is bad in two ways. Paths through it are not covered by ordinary timing analysis, and its behaviour at the moment the enable drops depends on which signal got there first.
How it happens
The synthesiser reasons simply: if there is any way through the block that ends without assigning an output, that output has to keep its old value, and keeping a value is storage. Two shapes of code do it.
An if without an else:
`timescale 1ns / 1ps
`default_nettype none
module incomplete_if (
input wire sel,
input wire a, b,
output reg y
);
always @(*) begin
if (sel)
y = a;
// sel = 0: y is not assigned, so it must hold: a latch
end
endmodule
You get a latch with sel as its enable and a as its data. Add the else:
always @(*) begin
if (sel)
y = a;
else
y = b;
end
and you get the mux you meant.
A case that does not cover every value:
module incomplete_case (
input wire [1:0] sel,
input wire [3:0] a, b, c,
output reg [3:0] y
);
always @(*) begin
case (sel)
2'b00: y = a;
2'b01: y = b;
2'b10: y = c;
// 2'b11: y holds, a latch
endcase
end
endmodule
Add a default:
case (sel)
2'b00: y = a;
2'b01: y = b;
2'b10: y = c;
default: y = 4'hx; // 2'b11, and any x or z
endcase
The difference in hardware is a feedback path from the output back to the input, closed when the enable is inactive (Figure 1).
The habit
Rather than remembering an else for every if and a default for every case, assign every output a value at the top of the block, before any condition:
`timescale 1ns / 1ps
`default_nettype none
module priority_enc_clean (
input wire [3:0] req,
input wire en,
output reg [1:0] grant,
output reg valid
);
always @(*) begin
grant = 2'b00; // defaults, on every path
valid = 1'b0;
if (en) begin
if (req[3]) begin grant = 2'b11; valid = 1'b1; end
else if (req[2]) begin grant = 2'b10; valid = 1'b1; end
else if (req[1]) begin grant = 2'b01; valid = 1'b1; end
else if (req[0]) begin grant = 2'b00; valid = 1'b1; end
end
end
endmodule
Whatever the conditions do, both outputs have already been assigned, so a latch is impossible. Every combinational block in this course starts this way, and once it is a habit the problem goes away.
The warnings
Yosys:
Warning: Latch inferred for signal `incomplete_if.y' from process `incomplete_if.$proc$incomplete_if.v:10$1'.
Vivado:
[Synth 8-327] inferring latch for variable 'y' [incomplete_if.v:10]
Quartus:
Warning (10240): Verilog HDL Always Construct warning at incomplete_if.v(10): inferring latch(es) for variable "y", which holds its previous value in one or more paths through the always construct
Each names the variable and the line. A synthesis run of combinational logic should produce none of them, and a build script that fails on “Latch inferred” is a good idea.
When a latch is meant
Transparent latches are used deliberately in time-borrowing pipelines, in some scan schemes, in DRAM sense amplifiers, and in the clock-gating cell of section 2.4. When you mean one, say so in a comment, write it as an explicit latch rather than as a side effect of a missing else, and suppress the warning for that block if the tool allows it. In this course, a latch you did not mean is a bug.
Before and after
`timescale 1ns / 1ps
`default_nettype none
// five latches: opcodes 4 to 7 assign nothing
module status_dec_buggy (
input wire [2:0] opcode,
output reg wr_en, rd_en, err, ack, stall
);
always @(*) begin
case (opcode)
3'b000: begin wr_en = 0; rd_en = 0; err = 0; ack = 1; stall = 0; end
3'b001: begin wr_en = 1; rd_en = 0; err = 0; ack = 0; stall = 0; end
3'b010: begin wr_en = 0; rd_en = 1; err = 0; ack = 0; stall = 0; end
3'b011: begin wr_en = 0; rd_en = 0; err = 1; ack = 0; stall = 0; end
endcase
end
endmodule
// no latches, and easier to read
module status_dec_clean (
input wire [2:0] opcode,
output reg wr_en, rd_en, err, ack, stall
);
always @(*) begin
wr_en = 1'b0;
rd_en = 1'b0;
err = 1'b0;
ack = 1'b0;
stall = 1'b0;
case (opcode)
3'b000: ack = 1'b1;
3'b001: wr_en = 1'b1;
3'b010: rd_en = 1'b1;
3'b011: err = 1'b1;
3'b100: stall = 1'b1;
// 5 to 7: everything stays at its default
endcase
end
endmodule
The clean version also reads better: the common case is stated once and each arm shows only what differs from it.
`timescale 1ns / 1ps
`default_nettype none
module tb_status_dec;
reg [2:0] opcode;
wire wr_en, rd_en, err, ack, stall;
status_dec_clean dut (
.opcode(opcode),
.wr_en(wr_en), .rd_en(rd_en), .err(err), .ack(ack), .stall(stall)
);
integer i;
initial begin
$dumpfile("tb_status_dec.vcd");
$dumpvars(0, tb_status_dec);
for (i = 0; i < 8; i = i + 1) begin
opcode = i[2:0];
#5;
$display("opcode=%03b wr=%b rd=%b err=%b ack=%b stall=%b", opcode, wr_en, rd_en, err, ack, stall);
end
opcode = 3'b111; #5; // an unlisted value
opcode = 3'b000; #5; // back; nothing should carry over
$display("after 111 then 000: wr=%b rd=%b err=%b ack=%b stall=%b", wr_en, rd_en, err, ack, stall);
$finish;
end
endmodule
Practice Exercise
For each block: does it infer a latch, on which signal, and how would you fix it with defaults?
// 1
always @(*) begin
if (mode == 2'b00) out = in_a;
if (mode == 2'b01) out = in_b;
if (mode == 2'b10) out = in_c;
end
// 2
always @(*) begin
led_r = 1'b0;
led_g = 1'b0;
led_b = 1'b0;
case (color)
2'b00: led_r = 1'b1;
2'b01: led_g = 1'b1;
2'b10: led_b = 1'b1;
2'b11: begin led_r = 1'b1; led_g = 1'b1; end
endcase
end
// 3
always @(*) begin
next_state = IDLE;
case (state)
IDLE: if (start) next_state = RUNNING;
RUNNING: if (done) next_state = IDLE;
endcase
end
// 4
always @(*) begin
if (a > b) begin
max_val = a;
min_val = b;
end else if (a < b) begin
max_val = b;
min_val = a;
end
end
Solution
Block 1 latches out: three separate ifs, and when mode is 3 none of them fires. Put out = in_a; at the top, or make it an if, else if chain with an else.
Block 2 is clean: defaults at the top and every value of color covered.
Block 3 is clean: next_state has a default before the case, so an unlisted state, or an arm whose if is false, leaves it at IDLE.
Block 4 latches both max_val and min_val: when a equals b neither branch runs. Assign both to a at the top; when they are equal either is a correct maximum and minimum.
Latches out of the way, the next section looks at if and case for what they build: priority chains and parallel decoders.