文章目錄
-
- 前言
- 正文
-
- 函數
-
- 文法
- 函數聲明
- 從函數中傳回一個值
- 函數調用
- 函數規則
- 任務
-
- 任務調用
- 全局任務
- 函數與任務之間的差別
- 往期回顧
- 參考資料及推薦關注
函數與任務是仿真中常用的文法,但合理使用也可以在設計中使用,可以綜合。
很多時候我們會發現某些代碼是重複的,在RTL中被多次調用。它們大多不消耗仿真時間,可能涉及複雜的計算,需要用不同的資料值來完成。在這種情況下,我們可以聲明一個函數,将重複的代碼放在函數裡面,讓它傳回結果。這将大大減少RTL中的行數,因為現在你需要做的就是進行函數調用,并傳遞需要在其上進行計算的資料。事實上,這與C語言中的函數非常相似。
函數的目的是傳回一個要在表達式中使用的值。一個函數定義總是以關鍵字
function
開始,後面是
傳回類型
、
名稱
和用括弧括起來的
端口清單
。當Verilog找到
endfunction
關鍵字時,就知道一個函數定義結束了。注意,一個函數至少要聲明一個輸入,如果函數沒有傳回任何東西,則傳回類型為
void
。
function [automatic] [return_type] name ([port_list]);
[statements]
endfunction
關鍵字automatic将使函數重入,在任務中聲明的項目被動态配置設定,而不是在任務的不同調用之間共享。這對于遞歸函數,以及當同一個函數在分叉時被N個程序并發執行時,将非常有用。
有兩種方式來聲明函數的輸入。
function [7:0] sum;
input [7:0] a, b;
begin
sum = a + b;
end
endfunction
function [7:0] sum (input [7:0] a, b);
begin
sum = a + b;
end
endfunction
函數定義将隐含地建立一個與函數同名的内部變量。是以,在函數的作用域内聲明另一個同名的變量是非法的。傳回值是通過将函數結果指派給内部變量來初始化的。
sum = a + b;
函數調用是一個帶有表達式的操作數,其文法如下圖所示。
reg [7:0] result;
reg [7:0] a, b;
initial begin
a = 4;
b = 5;
#10 result = sum (a, b);
end
- 函數不能包含任何時間控制的語句,如#, @, wait, posedge, negedge
- 函數不能調用任務,因為它可能會消耗仿真時間,但可以調用其他函數。
- 函數應該至少有一個輸入
- 函數不能有非阻塞性的指派或force…release或assign…deassign。
- 函數不能有任何觸發器
- 函數不能有output或者inout
函數的作用是對輸入進行一些處理,并傳回一個單一的值,而任務則更為通用,它可以計算出多個結果值,并使用output和inout類型的參數傳回。任務可以包含@、posedge等仿真耗時元素。任務有兩種寫法,我們接下來會看到。
// Style 1
task [name];
input [port_list];
inout [port_list];
output [port_list];
begin
[statements]
end
endtask
// Style 2
task [name] (input [port_list], inout [port_list], output [port_list]);
begin
[statements]
end
endtask
關鍵字automatic将使任務重入,否則它将預設為靜态的。如果一個任務是靜态的,那麼它的所有成員變量将在同一任務的不同調用中被共享,該任務已被啟動為并發運作。注意,auomatic任務項不能通過層次引用來通路。
如果任務不需要任何參數,那麼可以避免使用參數清單。如果任務需要參數,則可以在調用任務時在同一條語句中提供參數。
task sum (input [7:0] a, b, output [7:0] c);
begin
c = a + b;
end
endtask
// or
task sum;
input [7:0] a, b;
output [7:0] c;
begin
c = a + b;
end
endtask
initial begin
reg [7:0] x, y , z;
sum (x, y, z);
end
任務使能參數(x,y,z)對應于任務定義的參數(a,b,c)。由于a和b是輸入,x和y的值将分别放在a和b中。由于c被聲明為輸出,并且在調用過程中與z連接配接,是以總和将自動從c傳遞到變量z中。
在所有子產品之外聲明的任務稱為全局任務,因為它們具有全局範圍,可以在任何子產品中調用。
// This task is outside all modules
task display();
$display("Hello World !");
endtask
module des;
initial begin
display();
end
endmodule
仿真結果:
Hello World !
不能有時間控制語句/延遲,是以在同一仿真時間機關内執行。 | 可包含時間控制聲明/延遲,且隻能在其他時間完成。 |
無法啟用任務 | 可以實作其他任務和功能 |
至少要有一個輸入,函數不能有output或者inout。 | 可以有零個或多個任何類型的參數。 |
隻能傳回一個值 | 不能傳回一個值,但可以使用輸出參數達到同樣的效果。 |
Verilog初級教程(17)Verilog中的case語句
Verilog初級教程(16)Verilog中的控制塊
Verilog初級教程(15)Verilog中的阻塞與非阻塞語句
Verilog初級教程(14)Verilog中的指派語句
Verilog初級教程(13)Verilog中的塊語句
Verilog初級教程(12)Verilog中的generate塊
Verilog初級教程(11)Verilog中的initial塊
Verilog初級教程(10)Verilog的always塊
Verilog初級教程(9)Verilog的運算符
Verilog初級教程(8)Verilog中的assign語句
Verilog初級教程(7)Verilog子產品例化以及懸空端口的處理
Verilog初級教程(6)Verilog子產品與端口
Verilog初級教程(5)Verilog中的多元數組和存儲器
Verilog初級教程(4)Verilog中的标量與向量
Verilog初級教程(3)Verilog 資料類型
Verilog初級教程(2)Verilog HDL的初級文法
Verilog初級教程(1)認識 Verilog HDL
晶片設計抽象層及其設計風格
Verilog以及VHDL所倡導的的代碼準則
FPGA/ASIC初學者應該學習Verilog還是VHDL?
Verilog Functions
Verilog Task