Verilog: Task & Function

Task and Function are used to break up large procedures into smaller ones which helps to make life easier for developing and maintaining Verilog code. In this way, common procedures need to be written only once and can execute from different places. Both task and function are called from always or initial block and contain only behavioural statements.

Definition of task and function must be in a module. The highlighting difference between task and function is that, only task can handle event, delay or timing control statements and function executes in zero simulation time. There are some more differences, which we will be discussed in this sesssion.

Task

Task is declared using task & endtask keyword. Task must be used if delay, event or timing control constructs are required in the procedure. It may have zero or more than input,output or inout argument. As it executes in non-zero simulation time, it can enable other task and functions. It does not return value like function instead it can pass multiple value through output or inout arguments.

Automatic task

If a task is called concurrently from different places in the code these task calls will operate on the same task variables. This may leads to incorrect result. To avoid this problem a keyword automatic is added to make the task reentrant.

Function

Functions are declared using function & endfuncion keywords. Function can be used if there is no requirement for specifying delays, timing control constructs or events. There is at least one input argument is needed to use function. Function will return a single value and it usually uses for calculations. Also note that it cannot have output or inout arguments. As it cannot handle timing control statement, delays etc and executes in 0 simulation time, it can only enable another function and not task.

Below example shows how to calculate parity using function. A simple code, but always used in the designs.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

module parity_calc(Addr,Par);

input[31:0]Addr;

output Par;

reg Par;

always@(Addr)

Par=Parity_Calc_Func(Addr);

functionParity_Calc_Func;

input[31:0]addr;

Parity_Calc_Func=^addr;

endfunction

endmodule

//For testing

module test;

reg[31:0]Addr;

wire Par;

parity_calc pcalc(Addr,Par);

initial

$monitor($time," -->Addr = %b, Par = %b, ",Addr,Par);

initial begin

Addr=32'b1111_0000_0011_0111;

#10;

Addr = 32'b1111_0000_0011_0101;

#10;

Addr=32'b1111_0001_1111_0101;

#100 $finish;

end

endmodule

/*

//Simulation result

ncsim> run

0 -->Addr = 00000000000000001111000000110111, Par = 1,

10 -->Addr = 00000000000000001111000000110101, Par = 0,

20 -->Addr = 00000000000000001111000111110101, Par = 1,

Simulation complete via $finish(1) at time 120 NS + 0

./Parity_Calculation.v:36 #100 $finish;

*/

Automatic (Recursive) Functions

If normal functions are called recursively, the results are non-deterministic because both calls operate on the same variable space. But by using automatic keyword, all function declarations are allocated dynamically for each call and operate on independent variable space. Following is a well known example for automatic function.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

module Factorial_calc(Num,Factorial);

input[31:0]Num;

output integerFactorial;

//Automatic (recursive function)

functionautomatic integerFactorial_calc_Func;

input[31:0]n;

begin

if(n>=2)

Factorial_calc_Func=Factorial_calc_Func(n-1)*n;

else

Factorial_calc_Func=1;

end

endfunction

always@(Num)begin

Factorial=Factorial_calc_Func(Num);

end

endmodule

//For testing

module test;

reg[31:0]num;

wire[31:0]fact;

Factorial_calc fcalc(num,fact);

initial

$monitor($time," --> Factorial of Num %d = %d, ",num,fact);

initial begin

num=32'd6;

#10;

num = 32'd2;

#10;

num=32'd5;

#100 $finish;

end

endmodule

/* Simulation Result

ncsim> run

0 --> Factorial of Num 6 = 720,

10 --> Factorial of Num 2 = 2,

20 --> Factorial of Num 5 = 120,

Simulation complete via $finish(1) at time 120 NS + 0

./Factorial.v:45 #100 $finish;

*/

Constant Function

Constant function can be used to instead of constants. In the below example it calculates AWIDTH by using constant function.

hi,
please can you put an example of task calling a task?
and I have a question if you please, let us say that task#1 calls task#2, does task#2 executes in the same clock cycle of task#1 or it will be the next cycle ??
actually I want to implement two tasks say X and Y, task X should start in the first clock cycle then task Y will be repeated n times, each time in a different clock cycle … how this could be implemented ?
Thanks in advance. 🙂

This depends on how you invoke the tasks in your code. You can model it as per your requirement. You can model to call it at the same time or in the different clock cycles or after some specific time period etc.

Here your requirement is to invoke the task1 in the first clock cycle and task2 in the upcoming cycles. This can be implemented in the following method.

Thanks very much Sini Balakrishnan, it was very helpful.
but I don’t want task X to run at CLK #1 and stops, actually what I want is something like a thread;
Suppose each thread starts with task X in its first CLK then task y in the upcoming cycles.

I want to run multiple threads with a one CLK delay between one thread and the next.

Thanks for helping, I appreciate it.

Dana

April 23, 2015 at 11:43 am

I try to run the automatic recursive function and it gives me an error saying “recursive function call in function declaration is not supported”

Hello,
I am writing a memory in verilog using read and write task.
I am getting this error : Hierarchical name component lookup failed at ‘WRITE’.
I am not understanding why it is coming.Can you please tell me..

Hi Sini,
Your work is quite impressive. If possible pls clear my doubt. My o/p value always coming out as “X”. could you pls identify the source of error?
A few points add to validate my code. A single task called by two diff calls with different values passed by.
module vga_model(hsync,vsync);

Hi,
I am not sure about the logic which you are trying to implement. But with slight changes in the code, I could see TB gives values for hsync and vsync.
////////////////////////////////////////////////////
module vga_model(hsync,vsync);