Always block
Before we dive into always blocks, let's review basic digital logic design concepts. Understanding the distinction between combinational and sequential logic is fundamental to digital design and verification. It helps engineers decide which type of logic to use for a specific task or objective.
Combinatorial Logic: The output solely depends on the current input. There's no memory of past inputs. Basic gates like AND, OR, XOR are examples of combinational logic.
Sequential Logic: The output depends on both the current input and past inputs, thus having memory. Flip-flops, latches, and state machines, which can remember past states, use sequential logic.
always block
The always
block is a fundamental construct in Verilog and SystemVerilog used to model both combinational and sequential digital circuits. It allows for a block of code to be executed repeatedly in response to changes in its sensitivity list.
Here's a simplified structure of an always
block:
always @(sensitivity list)
begin
// Code to be executed
end
The sensitivity list can include one or more signals or events that, when they change or occur, trigger the execution of the code within the block.
always_comb
SystemVerilog introduces always_comb
and always_ff
for better readability and less error-prone code compared to Verilog's always
.
always_comb
automatically includes all variables in the block in the sensitivity list and behaves like combinational logic. This means it reacts immediately when any input changes, just like combinational hardware circuits.
module tb;
reg a, b;
wire y;
always_comb begin
y = a & b;
end
endmodule
In this example, y
is updated as soon as a
or b
changes.
always_ff
always_ff
, on the other hand, is used for describing sequential logic and expects an edge-triggered event in the sensitivity list. It is typically used with clock and reset signals.
module tb;
reg clk;
reg rst;
reg data;
always_ff @(posedge clk or negedge rst) begin
if (!rst)
data <= 0;
else
data <= data + 1;
end
endmodule
Here, data
gets updated on a rising edge of clk
or a falling edge of rst
.
Building on from the last tutorial, here is a structure of a module in SystemVerilog showing always block. We will expand on this diagram and add more blocks and containers as we move forward in this tutorial.
Types of Sensitivity Lists
Edge-Sensitive: Using
posedge
ornegedge
before a signal in the sensitivity list creates an edge-sensitive list, meaning the block will trigger on the rising or falling edge of that signal, respectively.Level-Sensitive: Without an edge keyword, the
always
block will trigger on any change in the specified signal. This is generally not recommended inalways_ff
oralways_comb
blocks due to the potential for unclear triggering conditions.
Let's create an example that demonstrates all three types: always @(*)
(level-sensitive), always @(posedge clk or negedge rst)
(edge-sensitive), and always_comb
.
module tb;
reg clk, rst, a, b;
reg [31:0] counter;
logic out1, out2;
// Level-sensitive block (used for combinational logic)
always @(*) begin
out1 = a ^ b;
end
// Edge-sensitive block (used for sequential logic)
always @(posedge clk or negedge rst) begin
if (rst == 1'b0)
counter <= 0;
else
counter <= counter + 1;
end
// Combinational block (another way to model combinational logic)
always_comb begin
out2 = a | b;
end
endmodule
Explanation:
always @(*)
: This block is sensitive to any changes ina
orb
. If either of these signals change,out1
is recomputed. This is often used for modeling combinational logic.always @(posedge clk or negedge rst)
: This block is sensitive to the rising edge(posedge)
ofclk
or the falling edge(negedge)
ofrst
. Ifrst
is low,counter
is reset to zero. If there's a rising edge onclk
(andrst
is not low),counter
increments by one. This is typically used to model sequential logic like flip-flops or registers.always_comb
: This block, introduced in SystemVerilog, is intended for modeling combinational logic. It implicitly includes all variables in its body as part of the sensitivity list. Here, ifa
orb
changes,out2
is recalculated as the OR ofa
andb
.
Comparing always block with always_comb
block
always
block gives you control over the specific conditions that trigger the execution of its statements, which can be useful for creating more complex or specialized testing scenarios. It requires you to explicitly state the sensitivity list, providing you with an avenue to mimic specific hardware scenarios.
always_comb
block automatically reacts to any changes in its inputs. This makes it ideal for verifying that a block of code behaves correctly in response to any change in its input signals. It reduces the risk of missing edge conditions in the sensitivity list, which can lead to untested scenarios in your testbench. This automatic sensitivity to changes in inputs helps to create robust, exhaustive test cases in your verification environment.
Pitfalls of using always blocks incorrectly
IMPORTANT: an always block is continuously active throughout simulation time. See below how always blocks and slow down or freeze your simulation.
An always
block can potentially hang a simulation when it leads to a situation known as an infinite loop. This happens when the conditions of the always
block continually satisfy the sensitivity list, causing the block to be executed indefinitely.
Here's an example:
module myModule;
reg a;
initial a = 0;
always @(a) begin
a = ~a;
end
endmodule
In this case, the variable a
is changed inside the always
block, and because a
is in the sensitivity list, this will cause the always
block to be triggered again. Consequently, this creates a non-stopping cycle of execution causing an infinite loop, which results in the simulation hanging.
It's essential to be mindful of the logic inside the always
block to prevent these scenarios. In real-world design and verification tasks, it's also a good practice to add timeout mechanisms to catch and handle such potential hang situations.
It's important to note that an always
block is continuously active throughout simulation time. Its behavior is closely tied to the event-driven nature of hardware description languages, where specific changes or events can trigger certain actions. In this context, always
blocks provide a way to describe how certain parts of a digital circuit should react to such changes or events.
Have a Question?
Feel free to ask your question in the comments below.
Please Login to ask a question.
Login Now