/// Notes and Demos for LSU EE 4702-1 Spring 2001 // Functions and Tasks // Sources: Ci: Ciletti, Modeling, synthesis, and rapid prototyping // with the Verilog HDL // LRM: IEEE, Verilog Language Reference Manual /// Contents // Functions // Tasks /// Functions // LRM 10.3 // Procedural code that returns a value. // Can be used in non-procedural code. // Restrictions on Functions // Has exactly one output variable. // Within a module. // No timing controls allowed. // Cannot use nonblocking assignments. // Cannot enable tasks. // Must have at least one input variable. // Cannot declare nets. /// Function Declaration // function RANGEORTYPE NAME; // ITEM_DECLARATIONS // STATEMENT // endfunction // // RANGEORTYPE: A range (e.g., [5:0]) or a type (e.g., integer, real, etc.) // ITEM_DECLARATIONS: input, variable, and parameter declarations. // (Cannot declare outputs, NAME is the function // name and the name of the single output.) // // Declare a function named NAME that returns a value of // type RANGEORTYPE. Inputs and variables for use by the function // are specified by ITEM_DECLARATIONS. The function returns // the value last assigned to NAME by STATEMENT. // Example of appropriate use of functions. module demo_func(); // Multiplexor function with a 16-bit output. function real realfunc; input a; real a; realfunc = a + 1.5; endfunction function [15:0] mux; input [1:0] control; input [15:0] in0,in1,in2,in3; begin case( control ) 0: mux = in0; 1: mux = in1; 2: mux = in2; 3: mux = in3; default: mux = 16'bx; endcase // case( control ) end endfunction // mux // Population count function. function [4:0] pop; input [31:0] a; // Works like a register. begin pop = 0; while( a ) begin pop = pop + ( a & 1 ); // Call by value, so it's okay to modify a. a = a >> 1; end end endfunction // pop // Note: Functions can be used in continuous assignments. // Execution starts whenever inputs change. // Execution completes in same time step. reg [31:0] x; wire [4:0] p2 = pop(x); reg [15:0] d1, d2, d3, d4; integer i; wire [15:0] v = mux(i[1:0],d1,d2,d3,d4); initial begin:INIT integer foo; integer p; foo = 32'b10101; // Functions can also be used in procedural code. p = pop(foo); $display("The population of %b is: %d",foo,p); x = foo; #0; $display("The population of %b is: %d",foo,p2); d1 = 100; d2 = 200; d3 = 300; d4 = 400; for(i=0; i<4; i=i+1) begin:B reg [15:0] v2; #0; $display("Continuous assign, for input %d output is %d",i,v); v2 = mux(i[1:0],d1,d2,d3,d4); $display("Procedural use, for input %d output is %d",i,v2); end end // block: INIT endmodule // demo_func `ifdef ERRORS module demo_func_errors(); function integer wont_work; input i; output j; // Outputs aren't declared. Use function name. output k; // Can't have two outputs; wire w; // Can't declare nets. begin #3; // No timing control in functions. k <= 4; // No nonblocking assignment allowed. end endfunction // wont_work endmodule // demo_func_errors `endif // ifdef ERRORS /// Tasks // LRM 10.2 // Something like C procedures, but there are major differences. // Unlike functions, cannot be used in an expression. // Unlike functions, can have outputs. // Unlike function, can contain timing controls. // Like functions, must be declared within a module. // Tasks cannot decalre net data types. // Arguments passed by value. // Tasks enabled (called) in procedural code (except procedural code // in functions). // In a statement enabling (calling) a task: // any expression can be used for an input arguments, // only an lvalue can be used for an output argument. // (An lvalue is an an expression that's valid on the left-hand side // of an assignment. That includes: // reg, integer, real, time, and realtime, // bit and part selects of above, // memory referenes (covered later), // concatenations of all above. // Example showing appropriate use of tasks, though functions for // pop and mux would be better. module demo_tasks(); task mux; output [15:0] mux_out; input [1:0] control; input [15:0] in0,in1, in2,in3; begin case( control ) 0: mux_out = in0; 1: mux_out = in1; 2: mux_out = in2; 3: mux_out = in3; // exemplar translate_off default: begin $display("Mux with unexpected input, %b",control); $stop; end // exemplar translate_on endcase // case( control ) end endtask // mux task pop; output [4:0] p; // Work like registers. input [31:0] a; // Work like registers. integer p; begin p = 0; while( a ) begin p = p + ( a & 1 ); // Note: call by value so it's okay to modify input. a = a >> 1; end end endtask // pop wire [4:0] w; // Use of pop and mux below roughly equivalent to continuous assignment // in task example. reg [31:0] x; reg [4:0] p2; always @( x ) pop(p2,x); reg [15:0] d1, d2, d3, d4; integer i; reg [15:0] v; always @( i or d1 or d2 or d3 or d4 ) mux(v,i[1:0],d1,d2,d3,d4); initial begin:INIT integer foo; integer p; foo = 32'b10101; // Output arguments (first here), must be something that // could be assigned to. For example, since // p = foo; is okay, pop(p,foo) is okay. pop(p,foo); // Since w is a wire, w = foo; here would be illegal and so // would: // pop(w,foo); ERROR: func.v(206): Illegal task output argument $display("The population of %b is: %d",foo,p); x = foo; $display("The population of %b is: %d",foo,p); d1 = 100; d2 = 200; d3 = 300; d4 = 400; for(i=0; i<4; i=i+1) begin:B reg [15:0] v2; #1; $display("Continuous assign, for input %d output is %d",i,v); mux(v2,i[1:0],d1,d2,d3,d4); $display("Procedural use, for input %d output is %d",i,v2); end end endmodule // demo