2024-12-26
Digital Design
L8: Tasks and Functions
Duong Ngoc Phap, Ph.D
Faculty of Computer Engineering and Electronics
December 26, 2024
Task and Functions
Learning Objectives
Describe the differences between tasks and
functions.
Identify the conditions required for tasks to be
defined. Understand task declaration and
invocation.
Explain the conditions necessary for
functions to be defined. Understand function
declaration and invocation.
1
2024-12-26
Task and Functions
A designer is frequently required to implement the same
functionality at many places in a behavioral design.
This means that the commonly used parts should be
abstracted into routines and the routines must be
invoked instead of repeating the code.
Most programming languages provide procedures or
subroutines to accomplish this.
Verilog provides tasks and functions to break up large
behavioral designs into smaller pieces.
Tasks and functions allow the designer to abstract
Verilog code that is used at many places in the design.
Tasks have input, output, and inout arguments; functions
have input arguments.
Thus, values can be passed into and out from tasks and
functions.
Considering the analogy of FORTRAN, tasks are similar
to SUBROUTINE and functions are similar to
FUNCTION.
Tasks and functions are included in the design hierarchy.
Like named blocks, tasks or functions can be addressed
by means of hierarchical names.
2
2024-12-26
Differences between Tasks and Functions
Both task and functions must be defined in a module and are
local to the module.
Tasks are used for common Verilog code that contains delays,
timing, event constructs, or multiple output arguments.
Functions are used when common Verilog code is purely
combinational, executes in zero simulation time and provides
exactly one output
Functions are typically used for conversions and commonly
used calculations.
Task can have input, output and in-out ports
Functions can have input ports. In addition they can have local
variables, integers, real or events.
Tasks and functions cannot have wires, they contain behavioral
statements only.
Tasks and functions do not contain always and initial
statements but are called form always block, initial block and
other task and functions.
3
2024-12-26
Task
Tasks are declared with the keywords task and endtask. Tasks
must be used if any one of the following conditions is true for
the procedure:
There are delay, timing, or event control constructs in the procedure.
The procedure has zero or more than one output arguments.
The procedure has no input arguments.
I/O declaration use keywords input, output or input, based on the type
of argument declared.
Input and output arguments are passed into the task.
Input arguments are processed in the task statements.
Output and inout argument values are passed back to the variables in
the task invocation statement when the task is completed.
Task can invoke other tasks or functions.
Ports are used to connect external signals to the module.
I/O arguments in a task are used to pass values to and from the task.
uments are processed in the task statements.
Task Declaration and Invocation
task_declaration ::=
task [ automatic ] task_identifier ;
{ task_item_declaration }
statement
endtask
| task [ automatic ] task_identifier (
task_port_list ) ;
{ block_item_declaration }
statement
endtask
4
2024-12-26
task_item_declaration ::=
block_item_declaration
| { attribute_instance } tf_input_declaration ;
| { attribute_instance } tf_output_declaration ;
| { attribute_instance } tf_inout_declaration ;
task_port_list ::= task_port_item { , task_port_item }
task_port_item ::=
{ attribute_instance } tf_input_declaration
| { attribute_instance } tf_output_declaration
| { attribute_instance } tf_inout_declaration
tf_input_declaration ::=
input [ reg ] [ signed ] [ range ]
list_of_port_identifiers
| input [ task_port_type ] list_of_port_identifiers
tf_output_declaration ::=
output [ reg ] [ signed ] [ range ]
list_of_port_identifiers
| output [ task_port_type ] list_of_port_identifiers
tf_inout_declaration ::=
inout [ reg ] [ signed ] [ range ]
list_of_port_identifiers
| inout [ task_port_type ] list_of_port_identifiers
task_port_type ::=
time | real | realtime | integer
5
2024-12-26
I/O declarations use keywords input, output, or inout,
based on the type of argument declared.
Input and inout arguments are passed into the task.
Input arguments are processed in the task statements.
Output and inout argument values are passed back to the
variables in the task invocation statement when the task is
completed.
Tasks can invoke other tasks or functions.
Although the keywords input, inout, and output used for
I/O arguments in a task are the same as the keywords
used to declare ports in modules, there is a difference.
Ports are used to connect external signals to the module.
I/O arguments in a task are used to pass values to and
from the task.
Task Examples
Use of input and output arguments
//Define a module called operation that contains the task
bitwise_oper
module operation;
...
parameter delay = 10;
reg [15:0] A, B;
reg [15:0] AB_AND, AB_OR, AB_XOR;
always @(A or B) //whenever A or B changes in value
begin
//invoke the task bitwise_oper. provide 2 input arguments A, B
//Expect 3 output arguments AB_AND, AB_OR, AB_XOR
6
2024-12-26
//The arguments must be specified in the same order as they //appear
in the task declaration.
bitwise_oper(AB_AND, AB_OR, AB_XOR, A, B);
end
...
//define task bitwise_oper
task bitwise_oper;
output [15:0] ab_and, ab_or, ab_xor; //outputs from the task
input [15:0] a, b; //inputs to the task
begin
#delay ab_and = a & b;
ab_or = a | b;
ab_xor = a ^ b;
end
endtask
...
endmodule
In the above task, the input values passed to the task
are A and B.
Hence, when the task is entered, a = A and b = B. The
three output values are computed after a delay.
This delay is specified by the parameter delay, which is
10 units for this example.
When the task is completed, the output values are
passed back to the calling output arguments.
Therefore, AB_AND = ab_and, AB_OR = ab_or, and
AB_XOR = ab_xor when the task is completed.
7
2024-12-26
Example 9-3. Task Definition using ANSI C
Style Argument Declaration
//define task bitwise_oper
task bitwise_oper (output [15:0] ab_and, ab_or, ab_xor,
input [15:0] a, b);
begin
#delay ab_and = a & b;
ab_or = a | b;
ab_xor = a ^ b;
end
endtask
Asymmetric Sequence Generator
Tasks can directly operate on reg variables defined in the module.
Example 8-4 directly operates on the reg variable clock to
continuously produce an asymmetric sequence.
The clock is initialized with an initialization sequence.
Example 9-4. Direct Operation on reg Variables
//Define a module that contains the task asymmetric_sequence
module sequence;
reg clock;
...
initial
init_sequence; //Invoke the task init_sequence
...
always
begin
asymmetric_sequence; //Invoke the task asymmetric_sequence
End
8
2024-12-26
//Initialization sequence
task init_sequence;
begin
clock = 1'b0;
end
endtask
//define task to generate asymmetric sequence
//operate directly on the clock defined in the module.
task asymmetric_sequence;
begin
#12 clock = 1'b0;
#5 clock = 1'b1;
#3 clock = 1'b0;
#10 clock = 1'b1;
end
endtask
Endmodule
Functions
Functions are declared with the keywords function
and endfunction.
Functions are used if all of the following conditions
are true for the procedure:
1. There are no delay, timing, or event control
constructs in the procedure.
2. The procedure returns a single value.
3. There is at least one input argument.
4. There are no output or inout arguments.
5. There are no nonblocking assignments.
9
2024-12-26
Function Declaration and Invocation
Example 9-6. Syntax for Functions
function_declaration ::=
function [ automatic ] [ signed ] [ range_or_type ]
function_identifier ;
function_item_declaration {function_item_declaration }
function_statement
endfunction
| function [ automatic ] [ signed ] [ range_or_type ]
function_identifier (function_port_list ) ;
block_item_declaration { block_item_declaration }
function_statement
endfunction
function_item_declaration ::=
block_item_declaration
| tf_input_declaration ;
function_port_list ::= { attribute_instance }
tf_input_declaration {,
{ attribute_instance } tf_input_declaration }
range_or_type ::= range | integer | real | realtime
| time
10
2024-12-26
When a function is declared, a register with name
function_identifer is declared implicitly inside Verilog.
The output of a function is passed back by setting the value of
the register function_identifer appropriately.
The function is invoked by specifying function name and input
arguments.
At the end of function execution, the return value is placed
where the function was invoked.
The optional range_or_type specifies the width of the internal
register.
If no range or type is specified, the default bit width is 1.
Functions are very similar to FUNCTION in FORTRAN.
Notice that at least one input argument must be defined for a
function. There are no output arguments for functions
because the implicit register function_identifer contains the
output value. Also, functions cannot invoke other tasks. They
can invoke only other functions.
Function Examples
Parity calculation
//Define a module that contains the function calc_parity
module parity;
...
reg [31:0] addr;
reg parity;
//Compute new parity whenever address value changes
always @(addr)
begin
parity = calc_parity(addr); //First invocation of calc_parity
$display("Parity calculated = %b", calc_parity(addr) );
//Second invocation of calc_parity
end
11
2024-12-26
//define the parity calculation function
function calc_parity;
input [31:0] address;
begin
//set the output value appropriately. Use the implicit
//internal register calc_parity.
calc_parity = ^address; //Return the xor of all address
bits.
end
endfunction
...
...
endmodule
Example 9-8. Function Definition using ANSI C Style
Argument Declaration
//define the parity calculation function using ANSI C Style
arguments
function calc_parity (input [31:0] address);
begin
//set the output value appropriately. Use the implicit
//internal register calc_parity.
calc_parity = ^address; //Return the xor of all address
bits.
end
endfunction
12
2024-12-26
Automatic (Recursive) Functions
Functions are normally used non-recursively . If a
function is called concurrently from two locations, the
results are non-deterministic because both calls operate
on the same variable space.
However, the keyword automatic can be used to declare
a recursive (automatic) function where all function
declarations are allocated dynamically for each recursive
calls.
Each call to an automatic function operates in an
independent variable space.Automatic function items
cannot be accessed by hierarchical references.
Automatic functions can be invoked through the use of
their hierarchical name.
Example 9-10. Recursive (Automatic) Functions
//Define a factorial with a recursive function
module top;
...
// Define the function
function automatic integer factorial;
input [31:0] oper;
integer i;
begin
if (operand >= 2)
factorial = factorial (oper -1) * oper; //recursive call
else
factorial = 1 ;
end
endfunction
13
2024-12-26
// Call the function
integer result;
initial
begin
result = factorial(4); // Call the factorial of 7
$display("Factorial of 4 is %0d", result); //Displays 24
end
...
...
endmodule
Constant Functions
A constant function[1] is a regular Verilog HDL function, but with
certain restrictions.
These functions can be used to reference complex val ues and can
be used instead of constants
Example:-Constant Functions-shows how a constant function
can be used to compute the width of the address bus in a module.
//Define a RAM model
module ram (...);
parameter RAM_DEPTH = 256;
input [clogb2(RAM_DEPTH)-1:0] addr_bus; //width of bus
computed
//by calling constant//function defined below//Result of clogb2 = 8
//input [7:0] addr_bus;
--
--
14
2024-12-26
//Constant function
function integer clogb2(input integer depth);
begin
for(clogb2=0; depth >0; clogb2=clogb2+1)
depth = depth >> 1;
end
endfunction
--
--
endmodule
Signed Functions
Signed functions allow signed operations to be
performed on the function return values.
Example 8-12 shows an example of a signed function.
Example 9-12. Signed Functions
module top;
//Signed function declaration
//Returns a 64 bit signed value
function signed [63:0] compute_signed(input [63:0]
vector);
--
--
endfunction
15
2024-12-26
//Call to the signed function from the higher
module
if(compute_signed(vector) < -3)
begin
--
end
endmodule
Recommended Questions
1. Describe the following statements with an example: initial and
always
2. What are blocking and non-blocking assignment statements?
Explain with examples.
3. With syntax explain conditional, branching and loop
statements available in Verilog HDL behavioural description.
4. Describe sequential and parallel blocks of Verilog HDL.
5. Write Verilog HDL program of 4:1 mux using CASE statement.
6. Write Verilog HDL program of 4:1 mux using If-else statement.
7. Write Verilog HDL program of 4-bit synchronous up counter.
8. Write Verilog HDL program of 4-bit asynchronous down
counter.
9. Write Verilog HDL program to simulate traffic signal controller
16
2024-12-26
Reference / Text Book Details
Sl.No
Title of Book Author Publication Edition
.
Verilog HDL: A Guide to Pearson
1 Digital Design and Synthesis Samir Palnitkar 2nd
Education
VHDL for Programmable PHI/Pearson
2 Logic Kevin Skahill 2nd
education
Springer
Donald E.
The Verilog Hardware Science+Busin
3 Thomas, Philip 5th
Description Language ess Media,
R. Moorby
LLC
Advanced Digital Design with Pearson
4 Michael D. Ciletti 2nd
the Verilog HDL (Prentice Hall)
Padmanabhan,
5 Design through Verilog HDL Wiley Latest
Tripura Sundari
Q&A
December 26, 2024
17