Verilog 14: Tasks & Functions — in-depth
- Get link
- X
- Other Apps
1. Introduction
In Verilog HDL (Hardware Description Language), designers frequently need to reuse code blocks, perform computations, or model specific behaviors. To achieve modularity and reduce repetitive coding, Verilog provides two procedural constructs: tasks and functions.
While both tasks and functions encapsulate reusable code, they serve different purposes:
-
Functions return a single value and execute in zero simulation time. They are ideal for combinational computations.
-
Tasks can handle multiple outputs, include timing control statements (like
#,@, andwait), and are used in sequential or complex behavioral modeling.
This tutorial provides a detailed exploration of tasks and functions, their syntax, usage, examples, and best practices — equipping hardware designers and students to model and simulate Verilog designs effectively.
2. Understanding Tasks in Verilog
A task is a procedural block in Verilog that encapsulates code which can be executed multiple times across a design. Tasks are versatile, supporting multiple outputs, timing controls, and even calling other tasks or functions.
Tasks are ideal for:
-
Modeling bus transactions
-
Stimulus generation in testbenches
-
Reusable behavioral code blocks
2.1. Syntax of a Task
task task_name; input [size] input_var; output [size] output_var; reg [size] local_var; // optional local variables begin // Task statements end endtask
Key points:
-
Declared inside a module or included via
`includefrom another file. -
Inputs and outputs are declared after the
taskkeyword. -
Local variables are private to the task.
-
Can contain timing controls (
@,#,wait) for sequential behavior.
2.2. Example 1: Simple Task
A common example is converting Celsius to Fahrenheit:
module simple_task(); task convert; input [7:0] temp_in; output [7:0] temp_out; begin temp_out = (temp_in * 9)/5 + 8'd32; // integer-safe formula end endtask endmodule
Explanation:
-
temp_inis the Celsius input,temp_outis the Fahrenheit output. -
Tasks can be called multiple times with different arguments.
-
Integer arithmetic requires careful ordering: multiply first, then divide.
2.3. Task Using Global Variables
Tasks can also operate on global variables without explicit inputs/outputs:
module task_global(); reg [7:0] temp_in, temp_out; task convert; begin temp_out = (temp_in * 9)/5 + 8'd32; end endtask endmodule
Note:
While this approach works, using global variables reduces modularity and can cause unexpected side effects. Best practice: use explicit I/O wherever possible.
2.4. Calling a Task
Tasks are invoked with a call statement. They cannot be used inside expressions.
Example: calling a task from another module:
module task_calling(temp_a, temp_b, temp_c, temp_d); input [7:0] temp_a, temp_c; output [7:0] temp_b, temp_d; reg [7:0] temp_b, temp_d; `include "mytask.v" // including external task file always @(temp_a) convert(temp_a, temp_b); always @(temp_c) convert(temp_c, temp_d); endmodule
Explanation:
-
The task
convertis included frommytask.v. -
It is called twice, each time with different input/output arguments.
-
Tasks reduce repetitive code, making designs cleaner and maintainable.
2.5. Advanced Example: CPU Write/Read Task
Tasks are extremely useful in testbenches for simulating sequential bus transactions.
module bus_wr_rd_task(); reg clk, rd, wr, ce; reg [7:0] addr, data_wr, data_rd; reg [7:0] mem [0:255]; initial begin clk = 0; rd = 0; wr = 0; ce = 0; #1 cpu_write(8'h11, 8'hAA); #1 cpu_read(8'h11, data_rd); #1 cpu_write(8'h12, 8'hAB); #1 cpu_read(8'h12, data_rd); #100 $finish; end // Clock generator always #1 clk = ~clk; // CPU Write Task task cpu_write; input [7:0] address, data; begin $display("%0t: CPU Write addr=%h data=%h", $time, address, data); @ (posedge clk); addr = address; ce = 1; wr = 1; data_wr = data; @ (posedge clk); addr = 8'h00; ce = 0; wr = 0; end endtask // CPU Read Task task cpu_read; input [7:0] address; output [7:0] data; begin $display("%0t: CPU Read addr=%h", $time, address); @ (posedge clk); addr = address; ce = 1; rd = 1; @ (negedge clk); data = mem[addr]; @(posedge clk); addr = 8'h00; ce = 0; rd = 0; $display("%0t: Read data=%h", $time, data); end endtask // Memory behavior always @(addr or ce or rd or wr or data_wr) begin if (ce) begin if (wr) mem[addr] = data_wr; if (rd) data_rd = mem[addr]; end end endmodule
Explanation:
-
Tasks allow reusing write and read sequences multiple times.
-
Timing controls (
@posedge clk) simulate realistic hardware behavior. -
This approach is typical for testbench modularity.
3. Understanding Functions in Verilog
Functions are similar to tasks but with key restrictions:
|
Feature |
Function |
Task |
|
Timing
controls (@, #) |
Not allowed |
Allowed |
|
Number of
outputs |
One (function
return) |
Multiple
(output/inout) |
|
Use in
expressions |
Yes |
No |
|
Can call |
Other
functions |
Functions
& tasks |
Functions are ideal for combinational computations such as arithmetic operations, parity generation, or ALU calculations.
3.1. Syntax of a Function
function [size] function_name; input [size] var1, var2; reg [size] local_var; // optional begin function_name = var1 + var2; // assign return value end endfunction
Key points:
-
Must return a value using the function name.
-
No timing delays allowed.
-
Can only call other functions, not tasks.
3.2. Example: Simple Function
module simple_function(); function [7:0] add_subtract; input [7:0] a, b, c, d; begin add_subtract = (a + b) - (c + d); end endfunction endmodule
-
Computes
(a+b) - (c+d)and returns it as output. -
Can be used in continuous assignments.
3.3. Calling a Function
Functions can be called inside expressions:
module function_calling(a, b, c, d, e, f); input [7:0] a, b, c, d, e; output [7:0] f; wire [7:0] f; `include "myfunction.v" assign f = (myfunction(a,b,c,d)) ? e : 0; endmodule
Explanation:
-
myfunction(a,b,c,d)returns a value used in a ternary operator. -
Functions enhance modularity and combinational logic design.
4. Differences Between Tasks and Functions
|
Feature |
Task |
Function |
|
Outputs |
Multiple (output/inout) |
Single
(return value) |
|
Timing |
Can
include @, #, wait |
Cannot
include delays |
|
Usage |
Called as
statement |
Can be used
inside expressions |
|
Calls |
Can call
tasks/functions |
Can call
functions only |
|
Typical usage |
Testbench
sequences, sequential operations |
Combinational
calculations |
5. Practical Tips for Tasks and Functions
-
Prefer I/O arguments over global variables for modularity.
-
Integer arithmetic caution:
(9/5)truncates to1. Multiply first:(x*9)/5. -
Tasks can model delays, e.g., bus handshakes. Functions cannot.
-
Use functions for combinational logic: parity, checksum, address calculation.
-
Synthesis considerations: tasks with
@/#are simulation-only, functions are synthesizable if purely combinational. -
Reentrancy caution: Classic Verilog tasks are not reentrant; recursive calls can cause conflicts.
6. Combined Example: Task + Function in a Testbench
module tb; reg [7:0] celsius; wire [7:0] fahrenheit; wire parity_bit; // Function for conversion function [7:0] c_to_f; input [7:0] c; begin c_to_f = (c * 9)/5 + 8'd32; end endfunction // Function for parity function parity_func; input [7:0] x; integer i; begin parity_func = 0; for (i=0;i<8;i=i+1) parity_func = parity_func ^ x[i]; end endfunction assign fahrenheit = c_to_f(celsius); assign parity_bit = parity_func(fahrenheit); // Task to display results task show_result; input [7:0] c; begin #1; // simulate propagation delay $display("C=%0d -> F=%0d Parity=%b", c, fahrenheit, parity_bit); end endtask initial begin celsius = 8'd0; show_result(celsius); celsius = 8'd25; show_result(celsius); celsius = 8'd100; show_result(celsius); $finish; end endmodule
Explanation:
-
c_to_fis a function for combinational conversion. -
parity_funccomputes a parity bit combinationally. -
show_resultis a task that prints values and includes small simulation delays. -
This design demonstrates modularity and correct use of tasks/functions in simulation.
7. Common Errors and Best Practices
| ||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
8. Summary
-
Tasks: Multiple outputs, can include timing, used in sequences and testbenches.
-
Functions: Single output, zero simulation delay, used in combinational expressions.
-
Tasks and functions reduce code repetition, improve readability, and promote modular design.
-
Careful use of integer arithmetic, timing controls, and scoping ensures correct simulation and synthesis behavior.
-
Together, tasks and functions are powerful tools for professional Verilog HDL modeling.
- Get link
- X
- Other Apps


Comments
Post a Comment