Subroutines are sections of code that can be defined and reused to perform specific tasks. They provide a way to modularize your code, making it more organized, readable, and easier to maintain. Subroutines are especially useful when you have a piece of functionality that needs to be executed multiple times or from different parts of your design.
Function is the basic block of code which performs the functionality that is programmed in it on every call. Verilog functions are similar to C/C++ or any other high level language functions in the sense
Support multiple arguments
Must define a return type or a default "void" is used
Can be invoked multiple times
Can be static or automatic ( automatic begin by default )
Primarily used in synthesis codes ( RTLs )
Verilog tasks are similar to function but with a couple of modifications which are explicitly meant to work with HDL simulators. They are mentioned below
Arguments must be declared as inputs, outputs or inputs
There is no return type for tasks
Tasks ar temporal, which means delays can be used in them
Tasks can be static or automatic
Tasks can call functions, but functions cannot call tasks
Mostly used to model verification or non synthesizable blocks
function integer rand_ret(); fork begin return 5; end begin return 6; end begin return 7; end join endfunction
module factorial_example; // Recursive function to calculate factorial function automatic integer factorial(input integer n); begin if (n == 0) factorial = 1; else factorial = n * factorial(n - 1); end endfunction initial begin $display("Factorial of 5 is: %0d", factorial(5)); end endmodule
module fibonacci_example; // Recursive function to calculate Fibonacci numbers function automatic integer fibonacci(input integer n); begin if (n == 0) fibonacci = 0; else if (n == 1) fibonacci = 1; else fibonacci = fibonacci(n - 1) + fibonacci(n - 2); end endfunction // Task to print Fibonacci series up to N-th element task print_fibonacci(input integer N); integer i; begin for (i = 0; i < N; i = i + 1) $display("Fibonacci(%0d) = %0d", i, fibonacci(i)); end endtask initial begin // Print Fibonacci series up to 10th element print_fibonacci(10); end endmodule
module top; function printF(); $display("PRINT CALL"); endfunction task print(); $display("TASK CALL"); endtask initial begin print(); // This works because there is no time being consumed in the task which is declared. Note that this is a LRM ambiguity, and so only some simulators allow it, for example older versions of QuestaSim. end endmodule
task cal_sum( input integer ARR_IN [8], output reg [31:0] ARR_SUM ); // Code endtask
task cal_sum( input integer ARR_IN [8], output reg [31:0] ARR_SUM ); integer i = 0; for( i = 0, ARR_SUM = 0; i < 8; i = i + 1 ) begin ARR_SUM = ARR_SUM + ARR_IN[i]; end return ARR_SUM; endtask module top; integer M[8] = '{ 1, 2, 3, 4, 5, 6, 7, 8 }; integer OUT; initial begin cal_sum( M, OUT ); $display( "Sum : %0d", OUT ); end endmodule
task gen_clk( ref integer clk_period, ref reg clk ); // Code endtask
task gen_clk( ref integer clk_period, ref reg clk ); clk = 0; forever begin #(clk_period/2) clk = ~clk; end endtask