1. verilog 基礎語法
阿新 • • 發佈:2018-11-23
1 模組結構
埠: module 模組名(埠1, 埠2, 埠3)
內容:
I/O說明:
input 埠名;
output 埠名;
內部訊號:
reg [width-1:0] r變數1,r變數2;
wire [width-1:0] w變數1,w變數2;
功能定義:
a. assign 連線
assign a = b&c;
b. 例項化其他元件
and and_inst(q, a, b);
c. always模組
always @(posedge clk or posedge clr)
begin
if(clr)
q <= 0;
else
if(en)
q <= d;
end
2.資料型別 常量 變數
常量:
整數:<位寬 num'><進位制 b|o|d|h><數字>,例如 4'b1010
x值(不定值)和z值(高阻值,也可用?代替)
x和z可以標識某一位或者某一個數字
4'b10x0,4'bx,4'b101z,4'bz,4'b?
負數:整數最前面加-
下劃線:分割數字部分,更加易讀(8'b1000_1000)
引數:parameter
parameter 引數名=表示式;
表示式只能是數字或者定義過的引數
變數:
wire型:wire [n-1:0] 資料名;
wire表示訊號,常用來表示assign關鍵字指定的組合邏輯訊號
wire型訊號可以用作輸入,輸出
reg型:reg [n-1:0] 資料名;
對儲存單元的抽象
常用來表示always模組內的指定訊號,常代表觸發器
always塊內被賦值的每一個訊號都必須定義為reg型
memory型:reg [n-1:0] 儲存器名[m-1:0];
reg [n-1:0]表示基本儲存單元的大小
儲存器名[m-1:0]表示基本儲存單元的個數,儲存空間的容量
對儲存器進行地址索引的表示式必須是常數表示式
一個n位暫存器可以在一條賦值語句裡進行賦值,而一個完整的儲存器不行
運算子及表示式:
基本運算子:+ - * / %
位運算子:~ & | ^ ^~
邏輯運算子:&& || !
關係運算符:< > <= >=
等式運算子:== != (不管x、z,結果可能是不定值)
=== !==(對引數的x、z都進行比較)
移位運算子:<< >>
位拼接運算子:{ },將幾個訊號拼接起來,例如{a,b[3:0],w,3'b100}
縮減運算子:C =&B;C =|B;C =^B;
優先級別:和c語言差不多,加括號
賦值語句:
1)非阻塞賦值方式(b <= a)
a.塊結束才完成賦值
b.b的值不是立刻就改變的
c.在可綜合的模組中常用
2)阻塞賦值方式(b = a)
a.賦值語句執行完成後,塊才結束
b.b的值在賦值語句執行後立刻改變
c.可能會產生意想不到的結果
簡單理解:
非阻塞賦值用了多個觸發器,每次時鐘到達,所有觸發器都觸發一次
阻塞賦值連到同一個觸發器上,時鐘到達,導致所有暫存器被賦值
塊語句:
順序塊:
1)塊內順序執行
2)每條語句的延遲是相對於前一條語句的模擬時間(語句前#num)
3)直到最後一句執行完,流程控制才跳出該塊
begin
語句1;
...
語句n;
end
或
begin:塊名:
塊內宣告;
語句1;
...
語句n;
end
並行塊:
1)塊內是同時執行的
2)語句的延遲是相對於程式流程控制進入塊內時的模擬時間
3)延遲時間是用來給賦值語句提供時序的
4)時序最後的語句執行完,或者disable語句執行時,跳出程式塊
fork
語句1;
...
語句n;
join
或
fork:塊名:
塊內宣告;
語句1;
...
語句n;
join
塊名:可以給每一塊取名,將名字加在begin和fork之後
1)可以在塊內定義區域性變數
2)可以被其他語句呼叫
3)在verilog中,所有變數靜態(都有唯一地址)
起始時間和結束時間:
並行塊和順序塊中有起始時間和結束時間
條件語句:
1)if...else 語句
if(表示式)
語句|語句塊
else
語句|語句塊
2)case語句
case|casez(case?)|casex,最常用的casez
case(控制表示式)
分支表示式1:語句|語句塊
...
分支表示式n:語句|語句塊
default: 語句
endcase
分支表示式的值的位寬必須相等,需要指明位寬
使用if時,最好也要使用else
使用case時,最好用上default
迴圈語句:
1)forever 連續的執行語句
forever
begin
多條語句
end
常用來生成周期型波形,用來作為模擬測試訊號
不能獨立寫在程式中,必須寫在initial塊中
2)repeat 執行一條語句n次
repeat(常量表達式)
begin
多條語句
end
3)while:執行一條語句直到某個條件不滿足(如果一開始條件不滿足,則一次也不執行)
while(表示式)
begin
多條語句
end
4)for
a) 迴圈次數變數初始值
b) 迴圈表示式判斷
c) 執行語句修正迴圈次數變數
使用方法和c語言基本一致
for(表示式1;表示式2;表示式3)
begin
多條語句
end
結構說明:
initial語句:
initial在模擬一開始就執行,但是隻執行一次
initial
begin
多條語句
end
always語句:
always <控制時序> <語句>
always 在模擬一開始就執行,always語句會不斷重複執行,所以需要時序的控制
不加時序控制,會不停重複執行,形成模擬死鎖
//邊沿觸發
always @(postedge clock or postedge reset)
begin
多條語句
end
//電平觸發
always @(postedge clock or postedge reset)
begin
多條語句
end
邊沿觸發的always塊常常用來描述時序邏輯
一個模組中可以有多個always塊,他們並行執行
task語句:
任務定義:
task <任務名>;
<埠及資料型別宣告語句>
<語句1>
...
<語句n>
endtask
任務呼叫:
<任務名> (埠1,...埠n)
例子:
//定義
task mytask;
input a,b;
inout c;
output d,e;
...
<語句> //執行任務工作相應的語句
...
c=foo1;
d=foo2;
e=foo3;
endtask
//呼叫
mytask(v,w,x,y,z);
function語句:
function定義:
function <返回值的型別或範圍> (函式名);
<埠說明語句>
<變數型別說明語句>
begin
多條語句;
end
endfunction
函式呼叫:
<函式名> (<表示式1>,...,<表示式n>)
函式的使用規則:
1)函式定義中不能包含有任何的時間控制語句
2)函式不能啟動任務
3)定義函式時至少有一個輸入引數
4)在函式的定義中必須有一條賦值語句給函式中的一個內部變數賦以函式的結果值
該函式變數具有和函式名相同的名字
例子:
//函式定義
function [7:0] getbyte;
input [15:0] address;
begin
<說明語句>
getbyte = result_expression;
end
endfunction
//函式呼叫:
word = control ? {getbyte(mybyte),getbyte(mybyte)} : 0;
系統函式和任務:
verilog語言中每個系統函式和任務前面都用一個識別符號$來加以確認
notice:引數為",,",表示空引數,輸出時顯示空格
1)$display 和 $write
作用:按照指定格式輸出,p1給出格式,p2...pn按序輸出
$display輸出後會自動換行,$write不換行
用法基本和c語言的printf一致
格式:
$display(p1,p2,...pn);
$write(p1,p2,...pn);
例子:
$display("rval=%h hex %d decimal",rval,rval);
2)系統任務 $monitor
用處:
提供了監控和輸出引數列表中的表示式或變數值的功能
模擬器建立了一種機制,使得每當引數列表中變數或者表示式的值發生變化時,
整個引數列表中變數或表示式的值都將輸出顯示。
任何時刻只能有一個$monitor起作用,因此需配合$monitoron和$monitoroff使用,
把需要監視的模組用$monitoron開啟,在監視完畢後及時用$monitoroff關閉
格式:
$monitor(p1,p2,...pn);
$monitor;
$monitoron;
$monitoroff;
例子:
$monitor($time,,"rxd=%b txd=%b",rxd,txd);
3)時間度量系統函式$time
verilog語言中支援兩種時間函式$time和$realtime
$time返回一個64位元值的整數來表示當前模擬時刻值
返回的總是時間尺度的倍數,並且會取整數
例子:
`timescale 10ns/1ns
module test
reg set;
parameter p=1.6;
initial
begin
$monitor($time,,"set=",set);
#p set=0;
#p set=1;
end
endmodule
$realtime返回的時間數字是個一個實型數
和$time一樣都是以時間尺度為單位
4)系統任務 $finish
$finish的作用是退出模擬器,返回主作業系統
$finish有3個引數,輸出的特徵資訊一次變多
引數:
0:不輸出資訊
1:輸出當前的模擬時刻和位置
2:輸出當前的模擬時刻和位置,在模擬過程中
所用的memory及CPU時間的統計
5)系統任務 $stop
把EDA工具(如模擬器)設定成暫停模式,在模擬環境中給出一個互動式的
命令提示符,將控制權交給使用者
和$finish一樣,引數為0,1,2,數越大,資訊越多
6)系統任務 $readmemb,$readmemh
用來從檔案中讀取資料到暫存器
讀取的檔案有格式要求(具體查書)
資料檔案的每個被讀取的數字都被存放到地址連續的儲存器單元中
每個資料的存放地址在資料檔案中進行說明
二進位制數字讀取
$readmemb("<資料檔名>",<儲存器名>);
$readmemb("<資料檔名>",<儲存器名>,<起始地址>);
$readmemb("<資料檔名>",<儲存器名>,<起始地址>,<結束地址>);
16進位制數字讀取
$readmemh("<資料檔名>",<儲存器名>);
$readmemh("<資料檔名>",<儲存器名>,<起始地址>);
$readmemh("<資料檔名>",<儲存器名>,<起始地址>,<結束地址>);
例子:
reg [7:0] mem[1:256];
initial $readmemh("mem.data",mem);
initial $readmemh("mem.data",mem,16);
initial $readmemh("mem.data",mem,128,1);
7)系統任務 $random
一個產生隨機數的手段,函式返回一個32bit的隨機數
$random的一般用法 $random % num,返回一個在(-num+1,num-1)範圍
內的隨機數
reg [23:0] rand;
rand = {$random} % 60; //利用拼接返回一個0到59之間的數
編譯預處理:
巨集定義 `define
`define 識別符號(巨集名) 字串內容(巨集內容)
“檔案包含”處理 `include
一個原始檔可以將另外一個原始檔全部包含起來
時間尺度:
`timescale <時間單位>/<時間尺度>
條件編譯:
`ifdef
`else
`endif
埠: module 模組名(埠1, 埠2, 埠3)
內容:
I/O說明:
input 埠名;
output 埠名;
內部訊號:
reg [width-1:0] r變數1,r變數2;
wire [width-1:0] w變數1,w變數2;
功能定義:
a. assign 連線
assign a = b&c;
b. 例項化其他元件
and and_inst(q, a, b);
c. always模組
always @(posedge clk or posedge clr)
begin
if(clr)
q <= 0;
else
if(en)
q <= d;
end
2.資料型別 常量 變數
常量:
整數:<位寬 num'><進位制 b|o|d|h><數字>,例如 4'b1010
x值(不定值)和z值(高阻值,也可用?代替)
x和z可以標識某一位或者某一個數字
4'b10x0,4'bx,4'b101z,4'bz,4'b?
負數:整數最前面加-
下劃線:分割數字部分,更加易讀(8'b1000_1000)
引數:parameter
parameter 引數名=表示式;
表示式只能是數字或者定義過的引數
變數:
wire型:wire [n-1:0] 資料名;
wire表示訊號,常用來表示assign關鍵字指定的組合邏輯訊號
wire型訊號可以用作輸入,輸出
reg型:reg [n-1:0] 資料名;
對儲存單元的抽象
常用來表示always模組內的指定訊號,常代表觸發器
always塊內被賦值的每一個訊號都必須定義為reg型
memory型:reg [n-1:0] 儲存器名[m-1:0];
reg [n-1:0]表示基本儲存單元的大小
儲存器名[m-1:0]表示基本儲存單元的個數,儲存空間的容量
對儲存器進行地址索引的表示式必須是常數表示式
一個n位暫存器可以在一條賦值語句裡進行賦值,而一個完整的儲存器不行
運算子及表示式:
基本運算子:+ - * / %
位運算子:~ & | ^ ^~
邏輯運算子:&& || !
關係運算符:< > <= >=
等式運算子:== != (不管x、z,結果可能是不定值)
=== !==(對引數的x、z都進行比較)
移位運算子:<< >>
位拼接運算子:{ },將幾個訊號拼接起來,例如{a,b[3:0],w,3'b100}
縮減運算子:C =&B;C =|B;C =^B;
優先級別:和c語言差不多,加括號
賦值語句:
1)非阻塞賦值方式(b <= a)
a.塊結束才完成賦值
b.b的值不是立刻就改變的
c.在可綜合的模組中常用
2)阻塞賦值方式(b = a)
a.賦值語句執行完成後,塊才結束
b.b的值在賦值語句執行後立刻改變
c.可能會產生意想不到的結果
簡單理解:
非阻塞賦值用了多個觸發器,每次時鐘到達,所有觸發器都觸發一次
阻塞賦值連到同一個觸發器上,時鐘到達,導致所有暫存器被賦值
塊語句:
順序塊:
1)塊內順序執行
2)每條語句的延遲是相對於前一條語句的模擬時間(語句前#num)
3)直到最後一句執行完,流程控制才跳出該塊
begin
語句1;
...
語句n;
end
或
begin:塊名:
塊內宣告;
語句1;
...
語句n;
end
並行塊:
1)塊內是同時執行的
2)語句的延遲是相對於程式流程控制進入塊內時的模擬時間
3)延遲時間是用來給賦值語句提供時序的
4)時序最後的語句執行完,或者disable語句執行時,跳出程式塊
fork
語句1;
...
語句n;
join
或
fork:塊名:
塊內宣告;
語句1;
...
語句n;
join
塊名:可以給每一塊取名,將名字加在begin和fork之後
1)可以在塊內定義區域性變數
2)可以被其他語句呼叫
3)在verilog中,所有變數靜態(都有唯一地址)
起始時間和結束時間:
並行塊和順序塊中有起始時間和結束時間
條件語句:
1)if...else 語句
if(表示式)
語句|語句塊
else
語句|語句塊
2)case語句
case|casez(case?)|casex,最常用的casez
case(控制表示式)
分支表示式1:語句|語句塊
...
分支表示式n:語句|語句塊
default: 語句
endcase
分支表示式的值的位寬必須相等,需要指明位寬
使用if時,最好也要使用else
使用case時,最好用上default
迴圈語句:
1)forever 連續的執行語句
forever
begin
多條語句
end
常用來生成周期型波形,用來作為模擬測試訊號
不能獨立寫在程式中,必須寫在initial塊中
2)repeat 執行一條語句n次
repeat(常量表達式)
begin
多條語句
end
3)while:執行一條語句直到某個條件不滿足(如果一開始條件不滿足,則一次也不執行)
while(表示式)
begin
多條語句
end
4)for
a) 迴圈次數變數初始值
b) 迴圈表示式判斷
c) 執行語句修正迴圈次數變數
使用方法和c語言基本一致
for(表示式1;表示式2;表示式3)
begin
多條語句
end
結構說明:
initial語句:
initial在模擬一開始就執行,但是隻執行一次
initial
begin
多條語句
end
always語句:
always <控制時序> <語句>
always 在模擬一開始就執行,always語句會不斷重複執行,所以需要時序的控制
不加時序控制,會不停重複執行,形成模擬死鎖
//邊沿觸發
always @(postedge clock or postedge reset)
begin
多條語句
end
//電平觸發
always @(postedge clock or postedge reset)
begin
多條語句
end
邊沿觸發的always塊常常用來描述時序邏輯
一個模組中可以有多個always塊,他們並行執行
task語句:
任務定義:
task <任務名>;
<埠及資料型別宣告語句>
<語句1>
...
<語句n>
endtask
任務呼叫:
<任務名> (埠1,...埠n)
例子:
//定義
task mytask;
input a,b;
inout c;
output d,e;
...
<語句> //執行任務工作相應的語句
...
c=foo1;
d=foo2;
e=foo3;
endtask
//呼叫
mytask(v,w,x,y,z);
function語句:
function定義:
function <返回值的型別或範圍> (函式名);
<埠說明語句>
<變數型別說明語句>
begin
多條語句;
end
endfunction
函式呼叫:
<函式名> (<表示式1>,...,<表示式n>)
函式的使用規則:
1)函式定義中不能包含有任何的時間控制語句
2)函式不能啟動任務
3)定義函式時至少有一個輸入引數
4)在函式的定義中必須有一條賦值語句給函式中的一個內部變數賦以函式的結果值
該函式變數具有和函式名相同的名字
例子:
//函式定義
function [7:0] getbyte;
input [15:0] address;
begin
<說明語句>
getbyte = result_expression;
end
endfunction
//函式呼叫:
word = control ? {getbyte(mybyte),getbyte(mybyte)} : 0;
系統函式和任務:
verilog語言中每個系統函式和任務前面都用一個識別符號$來加以確認
notice:引數為",,",表示空引數,輸出時顯示空格
1)$display 和 $write
作用:按照指定格式輸出,p1給出格式,p2...pn按序輸出
$display輸出後會自動換行,$write不換行
用法基本和c語言的printf一致
格式:
$display(p1,p2,...pn);
$write(p1,p2,...pn);
例子:
$display("rval=%h hex %d decimal",rval,rval);
2)系統任務 $monitor
用處:
提供了監控和輸出引數列表中的表示式或變數值的功能
模擬器建立了一種機制,使得每當引數列表中變數或者表示式的值發生變化時,
整個引數列表中變數或表示式的值都將輸出顯示。
任何時刻只能有一個$monitor起作用,因此需配合$monitoron和$monitoroff使用,
把需要監視的模組用$monitoron開啟,在監視完畢後及時用$monitoroff關閉
格式:
$monitor(p1,p2,...pn);
$monitor;
$monitoron;
$monitoroff;
例子:
$monitor($time,,"rxd=%b txd=%b",rxd,txd);
3)時間度量系統函式$time
verilog語言中支援兩種時間函式$time和$realtime
$time返回一個64位元值的整數來表示當前模擬時刻值
返回的總是時間尺度的倍數,並且會取整數
例子:
`timescale 10ns/1ns
module test
reg set;
parameter p=1.6;
initial
begin
$monitor($time,,"set=",set);
#p set=0;
#p set=1;
end
endmodule
$realtime返回的時間數字是個一個實型數
和$time一樣都是以時間尺度為單位
4)系統任務 $finish
$finish的作用是退出模擬器,返回主作業系統
$finish有3個引數,輸出的特徵資訊一次變多
引數:
0:不輸出資訊
1:輸出當前的模擬時刻和位置
2:輸出當前的模擬時刻和位置,在模擬過程中
所用的memory及CPU時間的統計
5)系統任務 $stop
把EDA工具(如模擬器)設定成暫停模式,在模擬環境中給出一個互動式的
命令提示符,將控制權交給使用者
和$finish一樣,引數為0,1,2,數越大,資訊越多
6)系統任務 $readmemb,$readmemh
用來從檔案中讀取資料到暫存器
讀取的檔案有格式要求(具體查書)
資料檔案的每個被讀取的數字都被存放到地址連續的儲存器單元中
每個資料的存放地址在資料檔案中進行說明
二進位制數字讀取
$readmemb("<資料檔名>",<儲存器名>);
$readmemb("<資料檔名>",<儲存器名>,<起始地址>);
$readmemb("<資料檔名>",<儲存器名>,<起始地址>,<結束地址>);
16進位制數字讀取
$readmemh("<資料檔名>",<儲存器名>);
$readmemh("<資料檔名>",<儲存器名>,<起始地址>);
$readmemh("<資料檔名>",<儲存器名>,<起始地址>,<結束地址>);
例子:
reg [7:0] mem[1:256];
initial $readmemh("mem.data",mem);
initial $readmemh("mem.data",mem,16);
initial $readmemh("mem.data",mem,128,1);
7)系統任務 $random
一個產生隨機數的手段,函式返回一個32bit的隨機數
$random的一般用法 $random % num,返回一個在(-num+1,num-1)範圍
內的隨機數
reg [23:0] rand;
rand = {$random} % 60; //利用拼接返回一個0到59之間的數
編譯預處理:
巨集定義 `define
`define 識別符號(巨集名) 字串內容(巨集內容)
“檔案包含”處理 `include
一個原始檔可以將另外一個原始檔全部包含起來
時間尺度:
`timescale <時間單位>/<時間尺度>
條件編譯:
`ifdef
`else
`endif