Procedural blocks in system verilog
In Verilog, there are initial and always procedural blocks as we have seen. In system Verilog, these procedural blocks were improved, and a few more procedural blocks were added. Some of these added procedural blocks are synthesizable and some are non-synthesizable. In this article we will see these blocks in detail.
Combinational logic
In Verilog, always
block was used to define both combinational and sequential circuits. But in always
block if we forget to add the else part it may be considered as latch during synthesis. Also, the sensitivity list needs to be provided correctly for the simulation to match the actual circuit.
To account for these problem System Verilog introduced a new always
block construct known as always_comb
.
Syntax
always_comb begin
...
end
Advantage over normal always construct
always_comb
automatically executes once at time-zero apart from normal execution whereasalways
executes only when there is change in the signal defined in the sensitivity list. This is helpful as in always block the value of signal is normally x until the block is triggered.always_comb
automatically infers the sensitivity list whereas inalways
block sensitivity list needs to be given manually. Sometimes some signal may be missed out in the always block leading to different result in simulation and actual hardware.always_comb
ensures that the variable on the left-hand side of the assignment is not written by another process. Whereas inalways
multiple process can write to the same variable.
Latch logic
System Verilog introduces always_latch
to write the latch logic. In always_latch
the sensitivity list is also automatically inferred from the signals used inside the block.
The only difference in always_latch
is that we need to have a if statement to support the enable signal for the latch
Syntax
always_latch begin
if(enable_cond) begin
...
end
end
Sequential Logic
System Verilog introduces always_ff
to write sequential logics which can be synthesized. Always_ff also ensures that the left side of the assignment is not written by any other process.
In always_ff we can have a iff
keyword to control the triggering of the block.
Syntax
always_ff @(event_control) begin
end
Example
module proc_mod(input wire clk, rst, a, b, c, en,
output reg op1, op2, op3);
always_comb begin
op1 = a + b;
end
always_latch begin
if(en) begin
op2 = c;
end
end
always_ff @(posedge clk or negedge rst) begin
if(!rst)
op3 = 0;
else begin
op3 = a + b + c;
end
end
endmodule
The test bench for the above code is not given. It is recommended to implement a test bench using the concepts discussed so far. In this scenario there is no specific requirement for the design to match. Thus, the test bench can be implemented in various ways.
Try this code in EDA PlaygroundFinal
Final is a new procedural block introduced in system Verilog. It is non synthesizable and is called at the end of the simulation. This block is basically used to carry out last moment house keeping activites. As it is non-synthesizable it is mainly used in test bench codes. One use could be to print the report of a test in the final block.
Syntax
final begin
end
Example
module final_block;
initial begin
$display("[%0t] Printing from intitial block", $time);
#30;
$finish();
end
final begin
$display("[%0t] Printing from final block", $time);
end
endmodule
Named blocks
In Verilog, we have seen that we can name procedural blocks using a :
. In System Verilog this has been extended and we can write the block name at the end of the block as well. This helps to improve the readability of the code as we can easily identify the opening and closing of a block.
Example
module abc;
initial begin:init_block
$display("Initial block");
end:init_block
endmodule
Simulators may give errors or warnings if the name at the end is different than the name of the block at the beginning.