UNIT-5
Procedures, Tasks, and Functions
Procedures, tasks, and functions are HDL tools to optimize the writing style of HDL code. They are implemented to instantiate a segment or a construct of code. Instead of writing the segment/construct every time it is needed, a single call statement to a function, task, or procedure that references the segment/construct is all that is needed.
Procedures and tasks can have more than one input and multiple output. Functions have a single output, but they can have multiple input.
Procedures and functions in VHDL can be called only from within process. Tasks and functions in Verilog can be called only from within always or initial.
Procedures (VHDL) and tasks (Verilog) are similar to subroutines in other software languages such as C. In many modules, a routine is repeatedly used. Instead of writing these routines every time they are needed, the routines’ codes can be stored as the body of a procedure (VHDL) or as the body of a task (Verilog). Whenever the routine needs to be executed, the procedure (task) is called by writing just one call statement.
Procedure (VHDL): Procedure is a behavioral statement. A procedure has two parts: the declaration and the body. The declaration includes the name of the procedure, the inputs to the procedure and their types, and the outputs of the procedure and their types. For example, the declaration: procedure Booth (X, Y : in signed (3 downto 0); Z: out signed (7 downto 0)) is declares a procedure by the name (identifier) Booth. The inputs are variables X and Y, each is four bits, and the type of the inputs is signed. The output is a four-bit variable Z, and its type is signed. In the declaration statement, procedure and is are predefined words and have to be inserted in the order shown. If the inputs or outputs are signals, they should be explicitly specified as follows: procedure exmple (signal a : in std_logic ; signal y: out std_logic) is The body of the procedure contains the behavioral statements that describe the details of the procedure, mainly the relationship between the input(s) and the output(s). The body of the procedure cannot include the behavioral statement process. An example of a procedure is: procedure exmple (signal a : in std_logic; signal y : out std_logic) is variable x : std_logic; begin x := a; case x is ………………… end case; y <= x; end exmple; The procedure is called by a sequential statement that appears inside process. For example, the above procedure exmple is called as follows: process (d, clk) begin ...... exmple (d, z); ......... end process
Task (Verilog) Task is a Verilog subprogram. It can be implemented to execute specified routines repeatedly. The format in which the task is written can be divided into two parts: the declaration and the body of the task. In the declaration, the name of the task is specified, and the outputs and inputs of the task are listed. An example of a task declaration is: task addr; output cc, dd; input aa, bb; addr is the name (identifier) of the task. The outputs are cc and dd, and the inputs are aa and bb. task is a predefined word. The body of the task shows the relationship between the outputs and inputs. An example of the body of a task is: begin cc = aa ^ bb; ............. end endtask The body of the task cannot include always or initial. A task must be called within the behavioral statement always or initial. An example of calling the task addr is: ............ always @ (a, b) begin addr (c, d, a, b); end addr is the name of the task. Inputs a and b are passed to aa and bb. The outputs of the task cc and dd are passed, after execution, to c and d, respectively. Verilog has a large number of built-in tasks included in its package.
Examples:
VHDL Description library IEEE; use IEEE.STD_LOGIC_1164.ALL; entity full_add is port (x, y, cin : in std_logic; sum, cout : out std_logic); end full_add; architecture two_halfs of full_add is -- The full adder is built from two half adders procedure Haddr (sh, ch : out std_logic; ah, bh : in std_logic) is --This procedure describes a half adder begin sh := ah xor bh; ch := ah and bh; end Haddr; begin addfull : process (x, y, cin) variable sum1, c1, c2, tem1, tem2 : std_logic; begin Haddr (sum1, c1, y, cin); Haddr (tem1, c2, sum1, x); --The above two statements are calls to --the procedure Haddr tem2 := c1 or c2; sum <= tem1; cout <= tem2; end process; end two_halfs;
Verilog Description
module Full_add (x, y, cin, sum, cout); //The full adder is built from two half adders input x, y, cin; output sum, cout; reg sum, sum1, c1, c2, cout; always @ (x, y, cin) begin Haddr (sum1, c1, y, cin); Haddr (sum, c2, sum1, x); //The above two statements are calls to the task Haddr. cout = c1 | c2; end task Haddr; //This task describes the half adder output sh, ch; input ah, bh; begin sh = ah ^ bh; ch = ah & bh; end endtask endmodule
2. Unsigned binary-vector-to-integer conversion Using procedure and task
VHDL: Converting an Unsigned Binary to an Integer Using procedure library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; --This Library is for -- type “unsigned” entity Bin_Int is generic (N : natural := 3); port (X_bin : unsigned (N downto 0); Y_int : out natural; Z : out std_logic); --Y is always positive end Bin_Int; architecture convert of Bin_Int is procedure bti (bin : in unsigned; int : out natural; signal Z : out std_logic) is -- the procedure bti is to change binary to integer -- Flag Z is chosen to be a signal rather than a variable -- Since the binary vector is always positive, -- use type natural for the output of the procedure. variable result : natural; begin result := 0; for i in bin’Range loop --bin’Range represents the range of the unsigned vector bin --Range is a predefined attribute if bin(i) = ‘1’ then result := result + 2i; end if; end loop; int := result; if (result = 0) then Z <= ‘1’; else Z <= ‘0’; end if; end bti; begin process (X_bin) variable tem : natural; begin bti (X_bin, tem, Z); Y_int <= tem; end process; end convert;
Verilog: Converting an Unsigned Binary to an Integer Using task
module Bin_Int (X_bin, Y_int, Z); parameter N = 3; input [N:0] X_bin; output integer Y_int; output Z; reg Z; always @ (X_bin) begin bti (Y_int, Z, N, X_bin); end task bti; parameter P = N; output integer int; output Z; input N; input [P:0] bin; integer i, result; begin int = 0; //change binary to integer for (i = 0; i <= P; i = i + 1) begin if (bin[i] == 1) int = int + 2**i; end if (int == 0) Z = 1’b1; else Z = 1’b0; end endtask endmodule
3. Integer-to-signed-binary conversion using Procedure
VHDL Code for Converting an Integer to a Signed Binary Using procedure library IEEE; use IEEE.STD_LOGIC_1164.ALL; use ieee.numeric_std.all; entity signed_IntToBin is generic (N : integer := 3); port (X_bin : out signed (N downto 0); Y_int : in integer); end signed_IntToBin; architecture convert of signed_IntToBin is procedure sitb (sbin : out signed; M, int : in integer) is -- The procedure sitb is to convert integer into signed -- binary. The dimension of “sbin” does not have to be -- specified at the declaration statement; it can be --declared later in the body of the procedure. variable temp_int : integer; variable flag : std_logic; variable bin : signed (M downto 0); begin if (int < 0) then temp_int := - int; flag := ‘1’; --if flag = 1, the number is negative else temp_int := int; end if; for i in 0 to M loop if (temp_int MOD 2 = 1) then bin (i) := ‘1’; else bin (i) := ‘0’; end if; --integer division by 2 temp_int := temp_int/2; end loop; if (flag = ‘1’) then sbin := - bin; else sbin := bin; end if; end sitb; begin process (Y_int) variable tem : signed (N downto 0); begin sitb(tem, N, Y_int); X_bin <= tem; end process; end convert; |
Functions are behavioral statements. As is the case when calling procedure or task, functions must be called within process (VHDL) or always or initial (Verilog). Functions take one or more inputs, and, in contrast to procedure or task, they return only a single output value.
VHDL Functions As in procedure, functions have a declaration and a body. An example of a function declaration is: function exp (a, b : in std_logic) return std_logic is where function is a predefined word, exp is the user-selected name of the function, and a and b are the inputs. Only inputs are allowed in the function declaration. The function returns a single output by the use of the predefined word return. The function exp returns a variable of type std_logic, and is is a predefined word that has to be at the end of the declaration statement. The name of the output is not listed in the declaration; it is listed in the body of the function. The body of the function lists the relationship between the inputs and the output to be returned. All statements in the body of the function should be behavioral (sequential) statements, and return is used to point to the output of the function.
Example of a VHDL Function library IEEE; use IEEE.STD_LOGIC_1164.ALL; entity Func_exm is port (a1, b1 : in std_logic; d1 : out std_logic); end Func_exm; architecture Behavioral of Func_exm is function exp (a, b : in std_logic) return std_logic is variable d : std_logic; begin d := a xor b; return d; end function exp; begin process (a1, b1) begin d1 <= exp (a1, b1); --The above statement is a function call end process; end Behavioral;
In above example, the name of the function is exp; it has two inputs, a and b, of type std_logic. The type of the output to be returned is std_logic. The output to be returned is d. The function, as seen from its body, is performing a xor function on the inputs a and b. To call the function, it should be written inside a process. The function is called by the following statement:
d1 <= exp (a1, b1);
The function call passes a1 and b1 to a and b, respectively, then calculates a1 XOR b1 and passes the output of the XOR to d1. The standard VHDL package has many built-in functions; other functions can be imported from packages attached to the VHDL module. Some examples of built-in functions are:
mod: finds the modulo of x mod y abs: finds the absolute value of a signed number To_INTEGER: returns an integer value of a signed input TO_SIGNED: takes an integer and returns its signed binary equivalent The package ieee.numeric_std.all has a large number of built-in functions.
Verilog Functions:
Functions in Verilog have a declaration statement and a body. In the declaration, the size (dimension), type, and name of the output are specified, as well as the names and sizes (dimensions) of the inputs. For example, the declaration statement
function exp; input a, b;
declares a function with the name (identifier) exp. The function has two inputs, a and b, and one output, exp. All inputs are one-bit data, and the output is also one-bit data. The inputs and output can take 0, 1, x (“don’t care”), or Z (high impedance). The body of the function follows the declaration in which the relationship between the output and the inputs is stated.
Example - Function to find the greater of two signed numbers
In this example, the greater of two signed numbers, x and y, is determined. Each number is a signed binary of four bits, and function is called in the main module to find the greater of the two input numbers. The result is stored in z.
VHDL Function to Find the Greater of Two Signed Numbers
library IEEE; use IEEE.STD_LOGIC_1164.ALL; use ieee.numeric_std.all; entity greater_2 is port (x, y : in signed (3 downto 0); z : out signed (3 downto 0)); end greater_2; architecture greater_2 of greater_2 is function grt (a, b : signed (3 downto 0)) return signed is -- The above statement declares a function by the name grt. -- The inputs are 4-bit signed numbers. variable temp : signed (3 downto 0); begin if (a >= b) then temp := a; else temp := b; end if; return temp; end grt; begin process (x, y) begin z <= grt (x, y); --This is a function call. end process; end greater_2;
Verilog Function to Find the Greater of Two Signed Numbers
module greater_2 (x, y, z); input signed [3:0] x; input signed [3:0] y; output signed [3:0] z; reg signed [3:0] z; always @ (x, y) begin z = grt (x, y); //This is a function call. end function [3:0] grt; /*The above statement declares a function by the name grt; grt is also the output of the function*/ input signed [3:0] a, b; /*The above statement declares two inputs to the function; both are 4-bit signed numbers.*/ begin if (a >= b) grt = a; else grt = b; end endfunction endmodule |
Files are implemented when dealing with a large amount of data that need to be stored and accessed. Also, files can be used to display formatted output, such as reports. Files can be read or written. To read from or write to a file, it must be opened, and after reading or writing is finished, the file must be closed. A closed file cannot be accessed unless it is opened.
VHDL File Processing File processing can be slightly different from one HDL simulator to another. Appropriate packages have to be attached to the VHDL module. The reader is advised to consult his or her VHDL package and simulator for files-handling capability. Files have to be declared by the predefined object type file. File declaration includes the predefined word file followed by the port direction or mode of the file (infile or outfile), a colon, and the subtype of the file. An example of file declaration is: file infile : text; The above statement declares a file with mode infile, and the subtype of the file is text. The IEEE package textio should be attached VHDL has built-in procedures for file handling. These procedures include file_open, readline, writeline, read, write, and file_close. (i) File_open
The file_open procedure opens the file; files cannot be accessed if not opened. This procedure has the following declaration: Procedure file_open (status : file_open_status, infile : file type, external_name : in string,open_kind : file_open_kind) is The statement status enables the VHDL to keep track of the activities of the file (e.g., open, close, read, etc.); infile is the type (mode) of the file. The infile is used for input files (their contents will be read), and outfile is used for output files. The external_name is the name of the file to be opened; the name has to be in string form such as “rprt.txt” or “testfi le.txt.” The open_kind is the mode of opening the read_mode or write_mode. An example of implementing file_open is: file_open (fstatus, infile, “testfile.txt”, read_mode);
(ii) File_close The procedure file_close is used to close an open file. For example: file_close (infile); closes the open file infile. The name and path of infi le are specified in the procedure file_open. The following statement closes outfile: file_close (outfile);
(iii) Readline The predefined procedure readline reads a line from the file opened in read mode. An example of implementing this procedure is: readline (infile, temp); The above statement reads a line from infile and stores the line in variable temp. Variable temp has to be of predefined type line. The name and type of infile should have been stated in the procedure file_open. Inside the file specified by infile, a carriage return is the separator between the lines. If readline is repeated before closing the file, another line is read. A carriage return indicates a new line.
(iv) Writeline The predefined procedure writeline writes a line into an outfile that is open for write mode. An example of implementing this procedure is: writeline (outfile, temp); The above statement writes a line stored in the variable temp into the file outfile. Variable temp has to be of type line. The name and path of outfile should be specified in the procedure file_open. Only integers, real values, or characters can be written into outfile. If writeline is repeated before closing outfile, a new line is stored in outfile. (v) Read To read an integer, a character, or a real value from a line in an infile that is open for read mode, the procedure read is used. For example, if intg1 has been declared as of type integer, the statement read (temp, intg1); performs a single read of an integer from line temp of the open file (for read mode) and stores the value of this integer in intg1. If a character or a real value is to be read, the variable intg1 should be of type character or real, respectively. If intg1 is a single value (not an array), each time the read operation is executed, a single word of the line is read and stored in intg1. If the read statement is repeated before closing the file, the next word in the line is read and stored in intg1. (vi) Write The procedure write stores an integer, a character, or a real value from a line to an outfile that is open for write_mode. For example, if intg1 has been declared as type integer, the statement write (temp, intg1); stores the integer intg1 in the line temp of the open outfi le, which is in write mode. If a character or a real value is to be written, the variable intg1 should be of type character or real, respectively. Each time the write operation is executed, a single word is stored in the line. If the write statement is repeated before closing the file, a new value of intg1 is stored in the line.
Verilog File Processing Standard Verilog can handle several file operations. As in VHDL, before accessing a file, it must be opened. If the file is not open, it cannot be read from or written to. Accessing a file is accomplished through built-in tasks such as $fopen, $fdisplay, $fmonitor, and $fclose. More tasks are being introduced in newer Verilog packages. Let us briefly investigate each of these tasks.
(i) $fopen The task $fopen is used to open files. It is the counterpart of the VHDL procedure file_open. The format for opening a file is: Channel = $fopen (“name of the fi le”); where Channel is a variable of type integer; it indicates the channel number. Verilog uses this channel number to track and identify which files are open. Verilog automatically assigns an integer value to each channel. For example, to open a text file named testfile: ch1 = $fopen (“testfile.txt”); and ch1 becomes the indicator (identifier) of file testfile.txt. (ii) $fclose The task $fclose closes a file indicated by the channel number. For example the task $fclose (ch1); closes the file testfile.txt. (iii) $fdisplay The task $fdisplay is the counterpart of write in VHDL. It can write variables, signals, or quoted strings. The format of $fdisplay is as follows: $fdisplay (channel, V1, V2, V3, ....); where V1, V2, V3, and so on are variables, signals, or quoted strings. For example, consider the following $fdisplay task: $fdisplay (ch1, “item description quantity”); After executing the task, the file testfile.txt displays: item description quantity The number of spaces displayed in the file between each string is the same number of spaces inside the quotations. (iv) $fmonitor The task $fmonitor has the following format: $fmonitor (channel, V1, V2, V3,…..) The task monitors and records the values of V1, V2, V3, and so on. For example, consider the following $fmonitor task: $fmonitor (ch1, “ %b”, quantity); The above task monitors the variable quantity and records its value in binary in the file testfi le.txt indicated by ch1, and %b indicates binary format. If quantity = 7 in decimal, after execution of the above task, the file testfile.txt displays: item description quantity 111 Different formats can be selected such as: %d - Display in decimal %s - Display strings %h - Display in hex %o - Display in octal %c - Display in ASCII character %f - Display real numbers in decimal format Escape characters may also used; some of these characters are: \n - Insert a blank line \t - Insert tab \\ - Insert the character \ \” - Insert the character “ \ - Insert the character % |
Consider a text file (written by a Notepad, for example) by the name of file_int.txt in the same path as the VHDL module that accesses it. The contents of the file are integers written in two lines. The two lines are separated by a carriage return, and the integers are separated by a space band.
VHDL Code for Reading and Processing a Text File Containing Integers
library ieee; use ieee.std_logic_1164.all; use std.textio.all; entity FREAD_INTG is port (START : in std_logic; z, z1, z2, z3 : out integer); end FREAD_INTG; architecture FILE_BEHAVIOR of FREAD_INTG is begin process (START) -- declare the infile as a text file file infile : text; --declare the variable fstatus (or any other variable name) --as of type file_open_status variable fstatus : file_open_status; variable count : integer; --declare variable temp as of type line variable temp : line; begin if (START = ‘1’) then --open the file file_int.txt in read mode file_open (fstatus, infile, “file_int.txt”, read_mode); --Read the first line of the file and store the line in temp readline (infile, temp); -- temp now has the data: 12 -3 5 -- Read the first integer (12) from the --line temp and store it in the integer variable count. read (temp, count); --count has the value of 12. Multiply by 2 and store in z z <= 2 * count; -- Read the second integer from the line temp and -- store it in count read (temp, count); --count now has the value of -3 --Multiply by 5 and store in z1 z1 <= 5 * count; -- read the third integer in line temp --and store it in count. read (temp, count); --Multiply by 3 and store in z2 z2 <= 3 * count; --Read the second line and store it in temp readline (infile, temp); --temp has only the second line --Read the first integer of the second line --and store it in count. read (temp, count); --Multiply by 4 and store in z3 z3 <= 4 * count; --Close the infile file_close (infile); end if; end process; end FILE_BEHAVIOR; After the code executes, z, z1, z2, and z3 take the following values: z = 24, z1 = –15, z2 = 15, z3 = 80
2. Reading a file containing ascii characters ASCII characters can be digits (e.g., 0, 1, 2), letters of the alphabet (e.g., A, B, C), or special characters (e.g., ; & #). The space band is an ASCII character and is read as a character.
Example code is for reading the file file_chr.txt. The file has two lines separated by a carriage return. The first line has three characters, A5B, and the second line has one character, M. If the first line contains A B instead of A5B, it is still read as three characters: A, space band, and B.
VHDL Code for Reading an ASCII File use ieee.std_logic_1164.all; use std.textio.all; entity FREAD_character is port (START : in std_logic; z, z1, z2, z3 : out character); end FREAD_character; architecture FILE_BEHAVIOR of FREAD_character is begin process (START) file infile : text; variable fstatus : file_open_status; variable count : character; -- Variable count has to be of type character variable temp : line; begin if(START = ‘1’) then file_open (fstatus, infile, “file_chr.txt”, read_mode); --read a line from the file readline (infile, temp); --read a character from the line into count. --Count has to be of type character. -- read (temp, count); --store the character in z z <= count; read (temp, count); z1 <= count; read (temp, count); z2 <= count; readline (infile, temp); read (temp, count); z3 <= count; file_close (infile); end if; end process; end FILE_BEHAVIOR;
After the code executes, z, z1, z2, and z3 take the following values: z = A, z1 = 5, z2 = B, z3 = M
|
References:
- HDL Programming (VHDL and Verilog)- Nazeih M.Botros- John Weily India Pvt. Ltd. 2008.
- Fundamentals of HDL – Cyril P.R. Pearson/Sanguin 2010.
- VHDL -Douglas perry-Tata McGraw-Hill
- A Verilog HDL Primer- J.Bhaskar – BS Publications
- Circuit Design with VHDL-Volnei A.Pedroni-PHI