本文目的
主要梳理之前學習Verilog的疏漏內容,系統瞭解Verilog語法。
Verilog的數據類型:
Verilog有兩組主要的數據類型:網絡數據類型(Net Data Type)和寄存器數據類型(Register Data Type)。其他的數據類型有:事件(Event)、參數(Parameter)和範圍(Specparam)以及其他數據類型。
Verilog還是用強度值來解決數字電路中不同強度的驅動源之間的賦值衝突
如果兩個具有不同強度的信號驅動同一個線網,則競爭結果值爲高強度信號的值。
如果兩個強度相同的信號之間發生競爭,則結果爲不確定值。
整數、實數和時間寄存器類型
整數
是一種通用的寄存器數據類型,用於對數量進行操作,使用integer進行聲明。
integer counter; //一般用途的變量用作計數器
initial
counter = -1; //把-1存儲到寄存器中
實數:
實常量和實數寄存器數據類型使用關鍵字real來聲明,可以用十進制或科學計數法
來表示。實數聲明不能帶有範圍,其默認值爲0.如果將一個實數賦予一個整數,
那麼實數將會被取爲最接近的整數。
real delta; //定義一個名爲delta的實型變量
時間寄存器
仿真是按照仿真時間進行的,verilog使用一個特殊的時間寄存器數據類型來保存仿真時間。
時間變量通過使用關鍵字time來聲明,其寬度與具體實現無關,最小爲64位。通過調用系統
函數$time可以取得當前的仿真時間。
數組
Verilog中允許聲明reg、integer、time、real、realtime及其向量類型的數組,對數組的維數沒有
限制,即可聲明任意維數的數組。線網數組也可用於連接實例的端口,數組中的每個元素都可以
作爲一個標量或者向量,以同樣的方式來使用,形如<數組名>[<下標>]。
Integer count[0:7]; //由八位計數變量組成的數組
reg bool [31:0]; //由32個1位的布爾寄存器變量組成的數組
wire [7:0] w_array2 [5:0]; //聲明8位向量的數組
注意:不要把數組和線網或寄存器向量混淆起來。向量是一個單獨的元件,它的位寬是n,數組由多個元件組成,其中每個元件的位寬爲n或1.
nets型
wire型數據常用來表示用於以assign關鍵字指定的組合邏輯信號。
Verilog程序模塊中輸入輸出信號類型默認爲wire型。
wire型信號可以用做方程式的輸入,也可以用做”assign”語句或者實例元件的輸出
reg型
reg是寄存器數據類型的關鍵字。
寄存器是數據存儲單元的抽象,通過賦值語句可以改變寄存器存儲的值,其作用相當於改變觸發器存儲器的值。
reg型數據常用來表示always模塊內的指定信號,代表觸發器。
通常在設計中要由always模塊通過使用行爲描述語句來表達邏輯關係。在always塊內被賦值的每一個信號都必須定義爲reg型,即賦值操作符的右端變量必須是reg型
reg型號數據的格式:
reg[n-1:0]數據名1,數據名2,…,數據N;
//定義了N個寄存器變量,每個數據位寬爲n
reg型數據的默認值是不定的。reg型數據可以爲正值或負值。當一個reg型數據是一個表達式中的操作數時,它的值被當做無符號值,即正值(如果一個4位的reg型數據被寫入-1,在表達式中運算時,其值被認爲是+15)
reg型和wire型的區別:reg型保持最後一次的賦值,而wire型需要持續驅動。
Memory型
儘管memory型數據和reg型數據的定義格式很相似,但是要注意不同之處。Memory描繪的是深度,reg描繪的是寬度。
Reg [ n-1:0 ] rega; //一個n位寄存器
Reg mema [ n-1 ] //一個由n個一位寄存器組成的存儲器組
一個n位的寄存器可以在一條賦值語句裏進行賦值。而一個完整的存儲器不行
Rega = 0;//合法的賦值語句
Mema=0;//非法的賦值語句
Mema[3]=0;//合法,給memory中的第三個單元賦值爲0
數組
Verilog中允許聲明reg、integer、time、real、realtime及其向量類型的數組,對數組的維數沒有限制,即可聲明任意維數的數組。線網數組也可用於連接實例的端口,數組中的每個元素都可以作爲一個標量或者向量,以同樣的方式來使用,形如<數組名>[<下標>]。
Integer count[0:7]; //由八位計數變量組成的數組
reg bool [31:0]; //由32個1位的布爾寄存器變量組成的數組
wire [7:0] w_array2 [5:0]; //聲明8位向量的數組
=注意:不要把數組和線網或寄存器向量混淆起來。向量是一個單獨的元件,它的位寬是n,數組由多個元件組成,其中每個元件的位寬爲n或1.==
向量
線網和寄存器類型的數據均可聲明爲向量(位寬大於1)。如果在聲明中沒有指定位寬,則默認爲標量(1位)
wire a; //標量線網變量,默認
wire [7:0] bus; //8位的總線
reg clock ; //標量寄存器,默認
reg [0:40] virtual_addr; //向量寄存器,41位寬的虛擬地址
向量通過[high#:low#]進行說明,方括號中左邊的數總是代表向量的最高有效位。
可變向量域選擇
Verilog的系統任務
系統任務也屬於行爲級建模,系統任務的調用要出現在initial與always結構中。所有的任務都已$開頭。
1、write用於信息的顯示和輸出。
%b或%B | 二進制 |
---|---|
%o或%O | 八進制 |
%d或%D | 十進制 |
%h或%H | 十六進制 |
%e或%E | 實數 |
%c或%C | 字符 |
%s或%S | 字符串 |
%v或%V | 信號強度 |
%t或%T | 時間 |
%m或%M | 層次實例 |
— | === |
---|---|
\n | 換行 |
\t | 製表符 |
\ | 反斜槓\ |
" | 引號” |
%% | 百分號% |
調用方式:eg:$display("%b+%b=%b",a,b,sum);
$write("%b+%b=%b",a,b,sum);
注:如果沒有在指定變量的顯示格式,不會輸出數值。如果沒有指定變量顯示的位置,變量值會在字符串部分之後直接顯示出來,變量之間是沒有間隔的,只是一次簡單的顯示。
顯示任務displayb,displaybh的顯示格式分別是二進制,八進制,十六進制。同理有writeo,writeh。
write的區別是:write不會換行.
2、$strobe探測任務
探測任務的語法和顯示任務完全相同,也是把信息顯示出來。也有strobeb,strobeh四種。
兩者的區別在於:display是隻要仿真器看到就會立即執行。
3、$monitor監測任務
監測任務用於持續監測指定變量,只要這些變量發生了變化,就會立即顯示對應的輸出語句,並且在仿真中只能進行一次調用,後面的調用會覆蓋前面的。
eg:
initial begin
$monitor("x=%b,y=%b,cin=%b",x,y,cin);
end
同理,有monitorbmonitorh。
可用$monitoroff,monitoeron關閉監事和打開監視。
4、finish仿真控制任務
區別:finish終止值當前方針。
`define:作用 -> 常用於定義常量可以跨模塊、跨文件;
範圍 -> 整個工程;
parameter: 作用 -> 常用於模塊間參數傳遞;
範圍 -> 本module內有效的定義;
localparam 作用 -> 常用於狀態機的參數定義;
範圍 -> 本module內有效的定義,不可用於參數傳遞;
localparam cannot be used within the module port parameter list.
2、應用舉例
`define、parameter、localparam三者的區別及舉例
`define
概念:可以跨模塊的定義,寫在模塊名稱上面,在整個設計工程都有效。
一旦`define指令被編譯,其在整個編譯過程中都有效。例如,通
過另一個文件中的`define指令,定義的常量可以被其他文件調用,
直到遇到 `undef;
舉例:定義 `define UART_CNT 10'd1024
使用 `UART_CNT
parameter
概念:本module內有效的定義,可用於參數傳遞;
如果在模塊內部定義時無法進行參數傳遞,
若在模塊名後照下面這樣寫則可以進行傳遞
舉例:定義
module video_in
#(
parameter MEM_DATA_BITS = 64,
parameter INTERLACE = 1 // 0
)
(
input clk,
input rst_n,
output burst_finsh
);
使用 -> 調用此模塊的時候可以像端口信號傳遞一樣進行參數傳遞
video_in
#( .MEM_DATA_BITS ( 64 ),
.INTERLACE ( 1 )
)
u_video_in (
.clk (clk_50m),
.rst_n (rst_n),
.burst_finsh (burst_finsh)
);
localparam:
概念:本module內有效的定義,不可用於參數傳遞;
localparamcannot be used within the module port parameter list.
一般情況下,狀態機的參數都是用localparam的。
舉例:
localparam BURST_LEN = 10'd64; /*一次寫操作數據長度 */
localparam BURST_IDLE = 3'd0; /*狀態機狀態:空閒 */
localparam BURST_ONE_LINE_START = 3'd1; /*狀態機狀態:視頻數據一行寫開始 */
localparam BURSTING = 3'd2; /*狀態機狀態:正在處理一次ddr2寫操作 */
localparam BURST_END = 3'd3; /*狀態機狀態:一次ddr2寫操作完成*/
localparam BURST_ONE_LINE_END = 3'd4; /*狀態機狀態:視頻數據一行寫完成*/
reg[2:0] burst_state = 3'd0; /*狀態機狀態:當前狀態 */
reg[2:0] burst_state_next = 3'd0; /*狀態機狀態:下一個狀態*/