6.1 Verilog Functions
Category Verilog Tutorial
Keywords: Function, Endian Conversion, Digital Tube Decoding
In Verilog, tasks (keyword: task) or functions (keyword: function) can be used to extract repetitive behavioral designs and call them in multiple places to avoid repeated code writing, making the code more concise and understandable.
Function
Functions can only be defined within a module, in any position, and referenced anywhere within the module. Their scope is limited to this module. Functions have the following characteristics:
- 1) Do not contain any delay, timing, or timing control logic
- 2) Have at least one input variable
- 3) Return only one value and have no output
- 4) Do not contain non-blocking assignment statements
- 5) Functions can call other functions but cannot call tasks
The format for declaring a Verilog function is as follows:
function [range-1:0] function_id;
input_declaration;
other_declaration;
procedural_statement;
endfunction
When declaring a function, an implicit register variable with a width of range and named function_id is declared. The function's return value is passed through this variable. If the width of this register variable is not specified, the default width is 1.
The function is called by specifying the function name and input variables. When the function ends, the return value is passed to the calling location.
The format for calling a function is as follows:
function_id(input1, input2, …);
Below is an example of using a function to implement a data endian conversion feature.
When the input is 4'b0011, the output can be 4'b1100. For example:
Example
module endian_rvs
#(parameter N = 4)
(
input en, //enable control
input [N-1:0] a ,
output [N-1:0] b
);
reg [N-1:0] b_temp;
always @(*) begin
if (en) begin
b_temp = data_rvs(a);
end
else begin
b_temp = 0;
end
end
assign b = b_temp;
//function entity
function [N-1:0] data_rvs;
input [N-1:0] data_in;
parameter MASK = 32'h3;
integer k;
begin
for(k=0; k<N; k=k+1) begin
data_rvs[N-k-1] = data_in[k];
end
end
endfunction
endmodule
Parameters within functions can also be rewritten, for example:
defparam data_rvs.MASK = 32'd7;
However, during simulation, it was found that this writing can compile, but the parameter MASK in the function did not actually rewrite successfully, still being 32'h3. This may be related to the compiler. Interested scholars can experiment with other Verilog compilers.
When declaring a function, a pair of parentheses can also be added after the function name to wrap the input declaration.
For example, the endian declaration function above can be expressed as:
function [N-1:0] data_rvs(
input [N-1:0] data_in
......
);
Constant Function
A constant function refers to a function whose result is a constant calculated during compilation before the simulation starts. Constant functions are not allowed to access global variables or call system functions, but they can call another constant function.
This type of function can be used to reference complex values and thus can be used to replace constants.
For example, the following constant function can be used to calculate the width of the address bus in a module:
Example
parameter MEM_DEPTH = 256;
reg [logb2(MEM_DEPTH)-1: 0] addr; //addr width is 8 bits
function integer logb2;
input integer depth;
//256 is 9 bits, our final data should be 8, so we need to stop the loop when depth=2
for(logb2=0; depth>1; logb2=logb2+1) begin
depth = depth >> 1;
end
endfunction
Automatic Function
In Verilog, the local variables of a general function are static, meaning that each call to the function uses the same storage space. If a function is called concurrently in two different places, the two function calls operating on the same address can lead to an uncertain function result.
Verilog uses the keyword automatic to describe such functions, which can automatically allocate new memory space when called, or can be understood as recursive. Therefore, the local variables declared in an automatic function cannot be accessed by hierarchical naming, but the automatic function itself can be called by hierarchical name.
Below is an example of using an automatic function to implement factorial calculation:
Example
wire [31:0] results3 = factorial(4);
function automatic integer factorial;
input integer data;
integer i;
begin
factorial = (data>=2)? data * factorial(data-1) : 1;
end
endfunction // factorial
Below are the simulation results with and without the automatic keyword.
As shown in the figure, the signal results3 obtained the result we wanted, which is the factorial of 4.
The signal results_noauto value is 1, which is not a predictable normal result, and no further analysis is needed here.
Digital Tube Decoding
The above-mentioned function knowledge does not seem to reflect the superiority of functions. Below is a design of a 4-bit decimal digital tube decoder to illustrate the advantage of functions in simplifying code.
The figure below is a physical diagram of a digital tube, which can display 4-bit decimal numbers. It is widely used in scoring and timekeeping competitions.
Each digital display has 8 light control terminals (shown as a-g in the figure), which can be used to control the display of numbers 0-9.
The digital tube has 4 chip selects (shown as 1-4), which are used to control which digital display should be enabled, i.e., should light up. If in a very short time, the 4 digital displays are sequentially selected for light emission, and different light controls are given under different chip selects (each corresponding to a 4-bit decimal number), then under the condition that the human eye cannot distinguish, the effect of simultaneously displaying 4-bit decimal numbers is achieved.
Below, we use the signal abcdefg to control the light control terminals and the signal csn to control the chip selects. The 4-bit decimal numbers of the ones, tens, hundreds, and thousands places are represented by 4 4-bit signals single_digit, ten_digit, hundred_digit, and kilo_digit, respectively. A digital tube display design can be described as follows:
Example
module digital_tube
(
input clk,
input rstn,
input en,
input [3:0] single_digit,
input [3:0] ten_digit,
input [3:0] hundred_digit,
input [3:0] kilo_digit,
output reg [3:0] csn, //chip select, low-available
output reg [6:0] abcdefg //light control
);
reg [1:0] scan_r; //scan_ctrl
always @ (posedge clk or negedge rstn) begin
if(!rstn)begin
csn <= 4'b1111;
abcdefg <= 'd0;
scan_r <= 3'd0;
end
else if (en) begin
case(scan_r)
2'd0:begin
scan_r <= 3'd1;
csn <= 4'b0111; //select single digit
abcdefg <= dt_translate(single_digit);
end
2'd1:begin
scan_r <= 3'd2;
csn <= 4'b1011; //select ten digit
abcdefg <= dt_translate(ten_digit);
end
2'd2:begin
scan_r <= 3'd3;
csn <= 4'b1101; //select hundred digit
abcdefg <= dt_translate(hundred_digit);
end
2'd3:begin
scan_r <= 3'd0;
csn <= 4'b1110; //select kilo digit
abcdefg <= dt_translate(kilo_digit);
end
endcase
end
end
/*------------ translate function -------*/
function [6:0] dt_translate;
input [3:0] data;
begin
case(data)
4'd0: dt_translate = 7'b1111110; //number 0 -> 0x7e
4'd1: dt_translate = 7'b0110000; // number 1 -> 0x30 4'd2: dt_translate = 7'b1101101; // number 2 -> 0x6d 4'd3: dt_translate = 7'b1111001; // number 3 -> 0x79 4'd4: dt_translate = 7'b0110011; // number 4 -> 0x33 4'd5: dt_translate = 7'b1011011; // number 5 -> 0x5b 4'd6: dt_translate = 7'b1011111; // number 6 -> 0x5f 4'd7: dt_translate = 7'b1110000; // number 7 -> 0x70 4'd8: dt_translate = 7'b1111111; // number 8 -> 0x7f 4'd9: dt_translate = 7'b1111011; // number 9 -> 0x7b endcase end endfunction
endmodule
Simulation results are as follows.
As shown in the figure, the chip select, decoding, and other signals all meet the design requirements. In practice, the 4-bit number should remain constant over a certain period, while the chip select signal continuously cycles through scanning, allowing the digital tube to present a static display effect to the human eye.
### Summary
If the decoder design does not use the function dt_translate, then when assigning values to the signals abcdefg in each case option, it is also necessary to judge the single_digit, ten_digit, hundred_digit, and kilo_digit. These judgment statements would be repeated four times. Although the actual hardware circuit synthesized in the end might be the same, the code using the function is clearly more concise and readable.
### Source Code Download
[Download](https://www.tutorialpro.org/wp-content/uploads/2020/09/6.1function.zip)
-[1.1 Verilog Tutorial](verilog-tutorial.html)
-[1.2 Verilog Introduction](verilog-intro.html)
-[1.3 Verilog Environment Setup](verilog-install.html)
-[1.4 Verilog Design Method](verilog-design-method.html)
-[2.1 Verilog Basic Syntax](verilog-basic-syntax.html)
-[2.2 Verilog Number Representation](verilog-number.html)
-[2.3 Verilog Data Types](verilog-data-type.html)
-[2.4 Verilog Expressions](verilog-expression.html)
-[2.5 Verilog Compile Instructions](verilog-compile-instruction.html)
-[3.1 Verilog Continuous Assignment](verilog-assign.html)
-[3.2 Verilog Time Delay](verilog-time-delay.html)
-[4.1 Verilog Process Structure](verilog-process-structure.html)
-[4.2 Verilog Process Assignment](verilog-process-assign.html)
-[4.3 Verilog Timing Control](verilog-timing-control.html)
-[4.4 Verilog Statement Blocks](verilog-statements-block.html)
-[4.5 Verilog Conditional Statements](verilog-condition-statement.html)
-[4.6 Verilog Multi-branch Statements](verilog-case.html)
-[4.7 Verilog Loop Statements](verilog-loop.html)
-[4.8 Verilog Procedural Continuous Assignment](verilog-deassign.html)
-[5.1 Verilog Modules and Ports](verilog-module-port.html)
-[5.2 Verilog Module Instantiation](verilog-generate.html)
-[5.3 Verilog Parameterized Instantiation](verilog-defparam.html)
- 6.1 Verilog Functions
-[6.2 Verilog Tasks](verilog-task.html)
-[6.3 Verilog State Machines](verilog-fsm.html)
-[6.4 Verilog Race and Hazard](verilog-competition-hazard.html)
-[6.5 Verilog Avoiding Latch](verilog-latch.html)
-[6.6 Verilog Simulation Stimulus](verilog-testbench.html)
-[6.7 Verilog Pipeline Design](verilog-pipeline-design.html)
-[7.1 Verilog Divider Design](verilog-dividend.html)
-[7.2 Verilog Parallel FIR Filter Design](verilog-fir.html)
-[7.3 Verilog Serial FIR Filter Design](verilog-serial-fir.html)
-[7.4 Verilog CIC Filter Design](verilog-cic.html)
-[7.5 Verilog FFT Design](verilog-fft.html)
-[7.6 Verilog DDS Design](verilog-dds.html)
-[8.1 Verilog Numerical Conversion](verilog-numerical-conversion.html)
-[Verilog Advanced Tutorial](verilog2-tutorial.html)
#### WeChat Subscription