[wpbread]
In SystemVerilog, always_comb
, always_latch
, and always_ff
are procedural blocks that are used for different types of hardware modeling. They provide different timing and sensitivity control to describe the behavior of combinational logic, latches, and flip-flops respectively. All forms of always procedures repeat continuously throughout the duration of the simulation. In this post we will discuss about these always procedures.
Table of Contents
always_comb
always_comb procedure is used for modelling combinational logic.
The always_comb procedure provides functionality that is different from the general purpose always procedure, as follows:
Example code: Here changing value of ‘a’ automatically triggers always_comb block.
module top;
int a, b, c, d;
always_comb begin
b = a;
c = b;
$display("%0t] a=%0d, b=%0d, c=%0d", $time, a, b, c);
end
initial begin
#1 a=1;
#1 a=2;
end
endmodule
Simulator output:
0] a=0, b=0, c=0
1] a=1, b=1, c=1
2] a=2, b=2, c=2
Example code: always_comb automatically triggered once at time zero.
module top;
int a, b, c, d;
always_comb begin
b = a;
$display("%0t] BLK1 a=%0d, b=%0d, c=%0d", $time, a, b);
end
always @* begin
c = d;
$display("%0t] BLK2 c=%0d, d=%0d", $time, c, d);
end
initial begin
#1 a=1; d=1;
#1 a=2; d=2;
end
endmodule
Simulator output:
0] BLK1 a=0, b=0
1] BLK1 a=1, b=1
1] BLK2 c=1, d=1
2] BLK1 a=2, b=2
2] BLK2 c=2, d=2
There is always_comb print is at time zero but not for always @.
Example code: Here “#1 b=1;“ inside initial block will cause compile time error.
module top;
int a, b, c, d;
always_comb begin
b = a;
c = b;
$display("%0t] a=%0d, b=%0d, c=%0d", $time, a, b, c);
end
initial begin
#1 b=1; //compilation error
#1 a=1;
#1 a=2;
end
endmodule
Simulator output:
Error-[ICPD] Illegal combination of drivers
testbench.sv, 2
Illegal combination of procedural drivers
Variable “b” is driven by an invalid combination of procedural drivers.
Variables written on left-hand of “always_comb” cannot be written to by any
other processes, including other “always_comb” processes.
This variable is declared at “testbench.sv”, 2: int b;
The first driver is at “testbench.sv”, 11: b = 1;
The second driver is at “testbench.sv”, 4: always_comb begin
b = a;
…
1 error
Example code:
always @*
is sensitive to changes in the arguments of the function.always_comb
is sensitive to changes within the contents of the function, including any internal variables that may change as a result of the function’s logic.
module top;
int x, y;
function automatic sum(input int X);
int s;
s=X+y;
//$display("[%0t] function - sum=%0d", $time, s);
endfunction
always @* begin
sum(x);
$display("[%0t] alwaya @", $time);
end
always_comb begin
sum(x);
$display("[%0t] alwaya_comb", $time);
end
initial begin
#1 $display("[%0t] x=1", $time);
x = 1;
#1 $display("[%0t] y=1", $time);
y = 1;
end
endmodule
Simulator Output:
[0] alwaya_comb
[1] x=1
[1] alwaya @
[1] alwaya_comb
[2] y=1
[2] alwaya_comb
When value of ‘x‘ is changed, both always@ and always_comb executed.
For value change of ‘y‘ , only always_comb is triggered.
Example code:
always @* & always_comb
are sensitive to changes in the arguments of the task, but not with any internal variables within task.
module top;
int x, y;
task automatic sum(input int X);
int s;
s=X+y;
//$display("[%0t] task - sum=%0d", $time, s);
endtask
always @* begin
sum(x);
$display("[%0t] alwaya @", $time);
end
always_comb begin
sum(x);
$display("[%0t] alwaya_comb", $time);
end
initial begin
#1 $display("[%0t] x=1", $time);
x = 1;
#1 $display("[%0t] y=1", $time);
y = 1;
end
endmodule
Simulator Output:
[0] alwaya_comb
[1] x=1
[1] alwaya @
[1] alwaya_comb
[2] y=1
When value of ‘x‘ is changed, both always@ and always_comb executed.
For value change of ‘y‘ , neither always@ or always_comb is triggered.
Example code:
Example code:
always_ff
The always_ff
block is used to model flip-flops, which are edge-triggered storage elements. It represents behavior where the output value is updated only on a clock edge (positive, negative, or both) based on the input values at that particular clock edge. The block is sensitive to the specified clock signal and executes on the positive (posedge) or negative (negedge) edge of the clock.
always_ff @(posedge clk)
begin
// Flip-flop logic statements
// Assignments, conditional statements, etc.
end
always_latch
The always_latch
block is used to model latches, which are level-sensitive storage elements. It represents behavior where the output value is determined by the input value only during a specific level of the clock. The block is triggered by changes in the variables used within the block and executes when any of these variables change.
always_latch
begin
// Latch logic statements
// Assignments, conditional statements, etc.
end
Thanks for providing nice explation with executable code.
Thanks for visiting this site.