1. Abstract
function和task語句的功能有很多的相似之處,在需要有多個相同的電路生成時,可以考慮使用它們來實現。因為個人使用它們比較少,所以對它們沒有進行更深的了解,現在時間比較充裕,我想通過寫幾個簡單的電路將它們二者的功能進行驗證一下,看看究竟是怎么生成電路的。
2. Contents
主要為測試function和task各自生成的電路,所以電路設計功能比較簡單——4位BCD碼轉換成4位余3碼。
文件開頭的注釋說明。
/* --------------------------------------- Module Name: temp Module Function: 將4位BCD碼轉換成為余3碼,無效狀態為4'b0000 Module Input: 4-bit data_in Module Output: 4-bit data_out Module Reference: None Note: 碼表如下 ######################################## data_in data_out 0 4'b0000 4'b0011 1 4'b0001 4'b0100 2 4'b0010 4'b0101 3 4'b0011 4'b0110 4 4'b0100 4'b0111 5 4'b0101 4'b1000 6 4'b0110 4'b1001 7 4'b0111 4'b1010 8 4'b1000 4'b1011 9 4'b1001 4'b1100 10 4'b1010 4'b0000 無效 11 4'b1011 4'b0000 無效 12 4'b1100 4'b0000 無效 13 4'b1101 4'b0000 無效 14 4'b1110 4'b0000 無效 15 4'b1111 4'b0000 無效 ---------------------------------------*/
2.1 直接使用組合邏輯電路生成BCD碼轉余3碼。
module temp(data_in,data_out); output reg [3:0] data_out; input [3:0] data_in; always @(data_in) begin if(data_in >= 4'd10) data_out = 4'b0000; else data_out = data_in + 4'd3; end endmodule
用RTL視圖查看一下生成出來的網表
生成出來的電路由加法器、比較器和選擇器構成,輸入數據data_in + 3作為選擇器的選擇控制,下面做一下驗證測試。
2.2 用task語句編寫組合電路
module temp(data_in,data_out); output reg [3:0] data_out; input [3:0] data_in; always @(data_in) begin if(data_in >= 4'd10) data_out = 4'b0000; else BCD2Access3(data_out,data_in); end task BCD2Access3; output [3:0] data_out; input [3:0] data_in; data_out = data_in + 4'd3; endtask endmodule
用RTL視圖查看一下最后生成的網表。
仔細對比,FIG2.3和FIG2.1是一模一樣的,也就是說采用task語句可以生成預期的邏輯圖,非常成功!既然生成出的邏輯圖都是一樣的,測試部分在此就省略了吧,和FIG2.2應該是一樣的。
2.3 用function語句編寫組合邏輯
module temp(data_in,data_out); output reg [3:0] data_out; input [3:0] data_in; always @(data_in) begin if(data_in >= 4'd10) data_out = 4'b0000; else data_out = BCD2Access3(data_in); end function [3:0] BCD2Access3; input [3:0] data_in; BCD2Access3 = data_in + 4'd3; endfunction endmodule
用RTL視圖查看一下最后生成出來的網表。
相信已經很熟悉這個邏輯圖了,與前面的FIG2.1一模一樣,也就是說使用function語句也是可以生成預期的電路的,而且也是非常成功的!既然邏輯圖都是與前面一致的,故測試部分……也省去了吧。
小結一下,用function和task語句都可以生成預期的邏輯電路,不過,查查語法書,可以知道task語句的適用性更廣泛一點,更符合邏輯思維的習慣;function最大的好處就是可以有一個返回值,運算以后結果可以直接返回供調用的塊使用。
在組合邏輯設計的過程中,寫成可綜合的電路可以達到預期的生成電路邏輯,那么在時序邏輯設計中,function和task語句又會生成出怎樣的電路呢?還是以這一個電路功能為模板,值得注意的是,得額外加一個時鍾信號。
2.4 直接使用時序邏輯編寫的BCD碼轉余3碼。
module temp(data_in,data_out,clk); output reg [3:0] data_out; input [3:0] data_in; input clk; always @(posedge clk) begin if(data_in >= 4'd10) data_out = 4'b0000; else data_out <= data_in + 3'd3; end endmodule
用RTL視圖來看下生成出來的邏輯網表。
和上面生成的邏輯網表相比,多了一個鎖存器,這也是典型的時序邏輯的特征,數據的變化只在clk的上升沿才有效。下面來做一下電路邏輯的驗證。
圖確實有點小,可能看起來有點不方便,但邏輯的功能是正確的,每到clk的上升沿,數據更新一次,譯碼是正確的,為了方便看,再截取一部分出來吧,作為一個局部放大圖。
直接用時序邏輯設計成功了,再嘗試着用task語句和function語句實現,看看最后的效果會怎么樣。
2.5 時序邏輯下使用task語句實現電路
module temp(data_in,data_out,clk); output reg [3:0] data_out; input [3:0] data_in; input clk; always @(posedge clk) begin if(data_in >= 4'd10) data_out = 4'b0000; else BCD2Access3(data_out,data_in); end task BCD2Access3; output [3:0] data_out; input [3:0] data_in; data_out = data_in + 4'd3; endtask endmodule
用RTL視圖來看一下生成的邏輯網表。
同樣,仔細對照一下,發現FIG2.8和FIG2.6是一樣的,也就是說在時序邏輯中使用task語句也是可以實現預期的電路的,非常的成功!和上述討論的一樣,既然邏輯圖相同的話,驗證的部分就略去了吧。
2.6 時序邏輯下用function語句實現電路
module temp(data_in,data_out,clk); output reg [3:0] data_out; input [3:0] data_in; input clk; always @(posedge clk) begin if(data_in >= 4'd10) data_out = 4'b0000; else data_out <= BCD2Access3(data_in); end function [3:0] BCD2Access3; input [3:0] data_in; BCD2Access3 = data_in + 4'd3; endfunction endmodule
跟上面一樣,用RTL視圖來看看最后生成出來的電路。
FIG2.9 時序邏輯下使用function語句生成的邏輯網表
仔細對比,會發現跟如上的邏輯網表一樣,也就是說在時序邏輯下使用function語句也是可以實現預期的電路的,非常的成功!邏輯網表一致的話,在此邏輯的驗證容我略去吧。
小結一下,在時序邏輯的電路設計中,也可以使用task語句和function語句來實現電路。
在學習過程中,也不斷的在看語法書,畢竟這一塊是我不太熟悉的地方,現在將它們使用的一些要點整理出來,對如何使用和最后生成怎樣的很有參考幫助。
task語句要點
(1)若用於任務中的命名變量或參數沒有在任務塊中聲明,則指的是在模塊中聲明的命名變量或參數。
(2)任務中的input,output和inout的個數不受限制(也可以為0個)。(任務可以沒有參數)
(3)任務中的變量(包括輸入(input)和雙向端口(inout))可以聲明為寄存器型。如果沒有明確地聲明,則默認為寄存器類型,且其位寬與相應的變量匹配。
(4)當啟動任務時,相應於任務的輸入和雙向端口(inout)的變量表達式的值被存入相應的變量寄存器中。當任務結束時,輸入和雙向端口(inout)的變量寄存器中的值又被代入啟動任務的語句中相應的表達式。
電路綜合參考:包含時序控制語句的任務是不可綜合的。啟動的任務往往被綜合成組合邏輯。
function語句要點
(1)函數必須至少有一個輸入變量,不能有任何輸出或輸入/輸出雙向變量(output 和inout類型)。
(2)函數不能包含時間控制語句(如延遲#、事件控制@或者等待wait)。
(3)函數是通過對函數名賦值的途徑返回其值的,就好比是一個寄存器。
(4)函數不能啟動任務。
(5)函數不能被禁用。(特指應用於編寫測試文件)
電路綜合參考:函數的每一次調用都被綜合為一個獨立的組合邏輯電路塊。
3.Conclusion
總體來說,task的功能更加符合硬件邏輯設計的習慣,而且語法中對它的限制比較少。而且它們最終生成的電路都是組合邏輯,所以在需要產生多個相同的模塊時,可以采用由它們構成。
4.Platform
Quartus II 9.1 Build 222 Full Version
5.Reference
[1] Verilog 數字系統設計教程(第2版) 夏宇聞
[2] Advanced Digital Design with the Verilog HDL (Second Edition) Michael D.Ciletti