The Sensitivity List
Section 5.1 took the @(...) after always for granted. This section is about it. An always block does not run continuously; it sleeps until something in that list changes. The list is the block’s statement of what kind of hardware it is, and the synthesiser reads it that way: get it right and you get the gates or the flip-flops you meant; get it wrong and you get a latch, or a simulation that quietly disagrees with the silicon.
The list
always @(a or b or c) begin
y = a & b & c;
end
After each pass through the body the block suspends, and it resumes only when a, b or c changes. Clocks ticking, other signals toggling, none of it is visible while it sleeps.
Four forms
Any change, @(signal): fires on either edge. Level-sensitive.
always @(a) begin
y = ~a;
end
Rising edge, @(posedge clk): fires on 0 to 1 only. Edge-sensitive, and the synthesiser builds a positive-edge flip-flop.
always @(posedge clk) begin
q <= d;
end
Falling edge, @(negedge clk): a negative-edge flip-flop. Rare in ordinary synchronous design; used at DDR interfaces and in a few reset schemes.
Several events, or between them in Verilog-95, a comma in Verilog-2001. This is the asynchronous-reset flip-flop:
always @(posedge clk or negedge rst_n) begin
if (!rst_n)
q <= 1'b0;
else
q <= d;
end
Both spellings are accepted by every current tool. The code in this course uses or in clocked lists; use whichever your team uses and be consistent.
What the form declares
No edge qualifier means combinational logic, or a latch if the body leaves an output unassigned on some path. An edge qualifier means a flip-flop (Figure 1). When you write @(posedge clk) you are not saying “wake on the edge”; you are saying “this is a register”. When you write @(a or b) you are saying “this is a function of the present inputs, no storage”, and the synthesiser holds you to that.
A correct combinational block
`timescale 1ns / 1ps
`default_nettype none
module and_gate (
input wire a,
input wire b,
output reg y
);
always @(a or b) begin
y = a & b;
end
endmodule
Both inputs are in the list, the body assigns y in every case, and the result is one AND gate. Now leave b out:
// broken
always @(a) begin
y = a & b;
end
The block runs only when a changes. If b changes while a holds, nothing runs and y keeps its old value. The simulation is now modelling storage that the synthesiser will not build. The third article of this section traces that in detail; for now, every signal read anywhere in a combinational block must be in its list.
The opposite mistake is an edge qualifier on a data signal. always @(posedge a) begin y = a & b; end is not combinational; it is a flip-flop clocked by a, and if a is data that is nonsense hardware. Tools warn about a clock driven from a non-clock net.
Practice Exercise
For each header, what form is it and what hardware does it infer, assuming the body suits it?
always @(posedge clk) begin ... end // A
always @(a or b or c or d) begin ... end // B
always @(negedge rst_n or posedge clk) begin ... end // C
always @(*) begin ... end // D
always @(posedge a) begin ... end // E, a is a data bus
Solution
A: edge-sensitive; a positive-edge flip-flop. B: level-sensitive on four signals; combinational logic if every output is assigned on every path, a latch otherwise. C: a flip-flop with asynchronous active-low reset. D: the automatic list, combinational, with the same caveat as B. E: a bug; a flip-flop clocked by a data bus.
The list in B has to be maintained by hand, and the next article is about the form that maintains itself.