Verilog HDL的程序結構及其描述
這篇博文是寫給要入門Verilog HDL及其初學者的,也算是我對Verilog HDL學習的一個總結,主要是Verilog HDL的程序結構及其描述,如果有錯,歡迎評論指出。
一、Verilog HDL的程序結構
首先我們不開始講Verilog HDL的語法,我們從Verilog HDL的程序結構出發。相信大家都看過芯片吧,它有個名字,有個外殼,外殼向外伸出有引腳(BGA封裝的那種請不要亂攪和...),然後芯片它可以實現一定的功能。
Ok,知道這些之後,我們就來看看Verilog HDL的描述數字電路的程序結構吧。
在解釋結構的時候,我拿芯片設計這個例子來打一個不恰當的比方。
VerilogHDL程序的大致結構就是這麽一個形式,每一個模塊的結構都是一致的只不過語句之間存在一些差別,每一部分的具體描述將在後面進行。
二、verilog程序結構的簡單描述
OK,現在讓我們現在開始了解一下一些語法和註意事項(註意,我這裏不會把語法講得很細很細,我主要是描述一些(我,或者初學者)易忘的,關鍵的語法和知識點),描述的順序不一定按照上面的各個部分喲,我們先描述一些VerilogHDL程序必須的。
首先是模塊說明:
module 和 endmodule ,這兩個關鍵詞成對出現,一般的內容都會囊括在這兩個兩個關鍵詞之間。一個verilog(.v)文件可以有多個module ...endmodule,但是為了方便管理,建議只實現一個。
此外無論是能夠綜合成電路的verilog程序還是只是仿真的程序,都需要以模塊的形式給出。
模塊名:
①模塊名的定義要符合標識符的定義,至於什麽是標識符,以後會說的。此外也要註意書寫的規範性。
端口說明:
①端口可以比方成芯片的輸入輸入管腳,它只有三種類型:輸入,輸出,雙向;
②端口有一些附加屬性,如數據類型、符號特性、位寬等;input端口只能是線網類型,output可以是寄存器類型也可以是線網類型,inout也只能是線網類型。至於線網類型和寄存器類型,在以後的數據類型中會介紹。
③當端口是總線類型時,可以簡單地理解為端口有多位時,對應於同時描述芯片的多個管腳時,可以給端口加上位寬。即input wire [M:N] a;如果M>N,則為降序,a[M]為最高位,位寬為M-N+1位;如果M<N,則最高位位a[N]位,位寬位N-M+1位;
④端口的屬性聲明順序可以是:
端口的輸入輸出 數據類型 有無符號 位寬 端口名稱 ;
如:output reg signed [7:0] a;
註:數據類型沒有寫則默認為wire 型,有無符號沒有寫默認為無符號型;位寬沒有寫默認為1bit 。
⑤當書寫完端口聲明是,括號後面的‘;’千萬不要忘記。
程序主體:
①前面我們提及到verilog的描述層次中有一個結構化描述,結構化的描述就是一點一點地例化(子模塊、單元門)來實現系統/設計的功能。程序的主體可以是只例化一些門單元,但是verilog的這種純結構化方式的顯然是無法滿足現代設計要求的,因此純結構化方式已經被遺棄。
②程序的主體可以是行為描述,也就是通過一些verilog的行為語句來實現設計的要求/功能。行為描述主要有:控制流描述,過程描述,塊語句,時序控制等。對於行為描述,有可綜合的,有不可綜合的,可綜合的行為描述語句/語法就可以認為是RTL級描述時用到的,而不可綜合的行為描述語句/語法可以認為是仿真/建模時用到的。
③下面大概說一下行為描述情況,也就是行為描述中無論是可綜合還是不可綜合都可以使用的情況,具體的可綜合和不可綜合的行為級描述語法在後面會描述。
控制流描述:以assign關鍵字開頭的語句描述稱為控制流描述,主要用來實現一些簡單的組合邏輯。
塊語句:包含在關鍵字begin...end 、fork ...join之間的語句稱為塊語句。
過程描述:由initial模塊、always模塊、function模塊、task模塊這四個模塊實現的過程。
時序控制:延時控制、敏感信號控制語句等
④塊語句可以有一個名字,寫在begin/fork後面(如beign:adder_disc ),給它一個名字有什麽好處呢?好處有兩個,一個是可以在塊內部定義寄存器變量(註意哦,只能寄存器變量,這個寄存器變量在塊內部使用),另外一個就是可以用disable這個關鍵字來中斷語句塊的執行(具體怎麽弄,請參看其他書籍,這裏不詳述)
⑤begin...end內的語句是串行的,這是從語法的結果上講的,但是它是可以綜合的,綜合出來的實際電路是並行的,也就是實際電路中,各條語句之間並不全是串行的,這裏需要建立一個概念,方便講解以後的阻塞賦值和非阻塞賦值。而fork...join 內的語句是同時進行的,然而這是不可綜合的。
⑥一個程序的主體中可以有多個initial模塊、always模塊、function模塊、task模塊。Function模塊和task模塊以後介紹。多個Initial模塊、always模塊之間是並行的,但是initial只執行一次,而always是反復執行。
initial一般是不可綜合的,用在仿真當中;在進行仿真時,通常被用來描述測試模塊的初始化、監視、波形生成等功能。
always用在可綜合的描述當中,一般情況下由敏感列表觸發(至於什麽是敏感列表,敏感列表怎麽用,請參考其他書籍,我後面也會做一些記載),也就是用在描述RTL級的描述當中,通常被用來對硬件的功能進行描述,可以實現組合邏輯和實現邏輯的功能。
上面沒有給出initial格式和always格式只是提了一下簡單應用。
⑦程序的主體大多可以由結構描述和行為描述構成
模塊的例化:
①模塊的例化主要是為實現總體的功能,比如說我要設計一塊芯片,這個芯片的某個功能可以有某個芯片來完成,那我就可以調用這個芯片,例化就是調用這麽一個概念。
②例化可以使用位置映射,也可使用名稱映射,由於位置映射可讀性太差,容易出錯,所有建議使用名稱映射。下面是名稱映射的格式:
被調用(例化)的模塊名字 自定義的例化模塊名(
.被調用(例化)模塊的端口名 (本模塊中的線網變量名),
...
.被調用(例化)模塊的端口名 (本模塊中的線網變量名)
);
③懸空處理:
在模塊例化時,如果被例化的模塊輸入管腳懸空,則該輸入為高阻Z,相當於與外界隔絕,但是實際電路中...
如果將輸出管腳懸空,則該輸出管腳將被廢棄掉。
④不同端口位寬處理
當模塊例化端口和被例化的端口位寬不同時,端口通過無符號數的右對齊截斷方式進行匹配。舉個例子說:
參數定義與映射:
①參數定義就是parameter 那一部分了,也就是可以用一個標識符表示一個固定的參數,當然`define這種宏定義也可以實現這種功能,這樣子提高程序的可維護性和可讀性。
使用`define時語法為:`define A 2‘b10 或者`define A 2.
一般把`define宏定義語句放在模塊最前面,並且要註意,無論是在子模塊還是頂層模塊中,A 的值都代表2(調用時為 `A)(全局參數)。
使用parameter定義的語法為 parameter A = 2或者parameter A= 2’d2;
一般放在模塊名字和模塊端口列表之間:模塊名 #(parameter A = XX,.....)(端口列表);使用parameter定義的參數只在當前模塊中有用(局部參數)
localparam定義時,上層模塊不能調用傳遞參數。
②參數傳遞:
參數傳遞就是在編譯或者仿真的時候,進行維護時,對參數空閑重新復制而更改其值。傳遞的參數是子模塊中定義的parameter,傳遞的方法有兩種:
(1)使用’#’符號:在同一模塊中使用’#’符號,參數賦值順序必須與原始模塊定義的順序相同,並不是一定要給所以的參數賦值,但是不允許跳過任何一個參數,即使是保持不變的值也要寫在相應的位置。說了這麽一大坨,還是舉個例子吧:
這樣子,A_WITH就是x1,B_WITH不改變,但是要寫在相應的位置。
(2)使用defparam關鍵字
直接上格式:
Verilog HDL的程序結構及其描述