1.1 概述
1.2 模塊Module
1.3 數據類型
1.3.1 wire/reg線網
wire和reg都是線類型,工程上沒區別;只是always/initial模塊中輸出定義需要為reg型;
注意:不要將reg類型與D觸發器混淆,reg理解為因為代碼所產生的。例如:
wire [7:0] a; //定義了8位的wire型數據 wireb; // 定義了1位的wire型數據 |
reg [3:0]sum;//定義了一個4位的reg型數據 |
類型
格式
說明
parameter
parameter數據名= 表達式
parameterMSB = 7;
常量
<位寬><進制><數字>
二進制:B或b;
十進制:D或d;
八進制:O或o;
8’b1010_1100 (‘b表示二進制)
<數字>
默認十進制;
4值邏輯
0:Logic Low
低電平;
1:Logic High
高電平;
x:Unknow;
不確定;
z:High Impedance;
高阻態; //三態門
1.4 運算符
//定義參數MSB為常量7;推薦大寫;
十六進制:H或h;
下畫線“_”,提高閱讀性。
1.4.1 概述
運算符 |
說明 |
算術運算符 |
+(加),-(減),*(乘),/(除),%(取模); |
每個運算符在電路中都是個模塊,如加法器,減法器; !注意:除法,除2^n,是移位運算, 浮點運算就復雜了,因此浮點運算要專用除法器; |
|
關系運算符 |
>, <, >=, <=,==(相等), !=(不相等); |
邏輯運算符 |
&&(邏輯與). ||(邏輯或), !(邏輯非); 條件判斷語句中,為避免歧義,邏輯運算符二邊推薦為1bit; |
位運算符 |
&(與),|(或), ~(非), ^(異或); ~^(同或); |
移位運算符 |
<<(左移),>>(右移); |
歸約操作 |
&,~&, |, ~|,^, ~^;//unary reduction; |
條件運算符 |
?: |
拼接運算符 |
{} //{3{a[0]}}:代表3根同樣的a[0]線,{a[0],a[0],a[0]} |
1.5.1 assign(連續賦值)
1.1.1 always(過程塊)
賦值方式 |
說明 |
=,阻塞賦值 |
always @(a or b or C or …) begin 語句塊(=, if語句, case語句) end |
實現:組合邏輯電路;(注意!禁止用于時序邏輯電路) always塊內,阻塞賦值:是順序執行(類似C); |
|
敏感表:@(*) //“*”自動添加相關輸入信號; |
|
避免出現Latch(鎖存器) 分支語句(if語句,case語句)條件不滿時,會在電路中自動生成鎖存器來保存不滿足條件的值,因此要補全if-else,和case的defalut語句; |
|
<=,非阻塞賦值 |
always @(posedge clk or negedge rst_n) begin 語句塊(<=, if語句, case語句) end |
實現:時序邏輯電路;(注意!禁止用于組合邏輯電路) always塊內,阻塞賦值:并行執行; |
if語句
條目 |
說明 |
格式1 |
if(條件)begin 語句1; 語句2; end else begin 語句1; 語句2; end |
格式2 |
if(條件)begin 語句1; 語句2; end else if begin 語句1; 語句2; end else begin 語句1; 語句2 end |
特點 |
分支語句,各個分支條件不同;順序執行判斷; |
注意 |
if-else成對使用; |
case語句
條目
說明
格式
case(表達式)
常量表達式1:begin
語句;
end
常量表達式2:begin
語句;
end
常量表達式3:begin
語句;
end
default:
語句;
endcase
特點
分支語句,各個分支條件相同;并行執行判斷;
注意
default語句不可省略;
代碼&硬件

條目 |
說明 |
格式 |
case(表達式) 常量表達式1:begin 語句; end 常量表達式2:begin 語句; end 常量表達式3:begin 語句; end default: 語句; endcase |
特點 |
分支語句,各個分支條件相同;并行執行判斷; |
注意 |
default語句不可省略; |
1.5.3 模塊例化
作用
系統設計時,建議遵循以下設計原則:

1.5.4 全加器
描述方式
描述方式
說明
位置關聯
AND u1(a, b, and_out);
名字關聯
AND u1(.a(a), .b(b), .o(and_out)); //推薦使用
1.6.1 結構
描述方式 |
說明 |
位置關聯 |
AND u1(a, b, and_out); |
名字關聯 |
AND u1(.a(a), .b(b), .o(and_out)); //推薦使用 |
1.6.2 特殊符號
語句
說明
`<標識符>
表示:
編譯引導語,用于指導仿真編譯器在編譯時采取一些特殊處理;
編譯引導語句一直保持有效,直到被取消或重寫;
`timescale
`timescale <時間單位>/<時間精度>
例1:
`timescale 1ns/1ns //時間單位1ns;時間精度1ns;
#2 //延時2 ×1=2ns;
#2.1//延時2.1 × 1 = 2.1ns,精確到1ns,為2ns;
例2:
`timescale 1ns/100ps //時間單位1ns;時間精度100ps;
#2 //延時2 ×1= 2ns;
#2.1//延時2.1 × 1 = 2.1ns,精確到100s,為2.1ns;
`define
`include
`include “global.v”
包含另一個文件,完整拷貝過來;
`restall
把所有設置的編譯引導恢復到缺省狀態;
#<num>;
#10; //延遲10個時間單位
1.6.3 語句
語句 |
說明 |
`<標識符> |
表示: 編譯引導語,用于指導仿真編譯器在編譯時采取一些特殊處理; 編譯引導語句一直保持有效,直到被取消或重寫; |
`timescale |
`timescale <時間單位>/<時間精度> 例1: `timescale 1ns/1ns //時間單位1ns;時間精度1ns; #2 //延時2 ×1=2ns; #2.1//延時2.1 × 1 = 2.1ns,精確到1ns,為2ns; 例2: `timescale 1ns/100ps //時間單位1ns;時間精度100ps; #2 //延時2 ×1= 2ns; #2.1//延時2.1 × 1 = 2.1ns,精確到100s,為2.1ns; |
`define |
|
`include |
`include “global.v” 包含另一個文件,完整拷貝過來; |
`restall |
把所有設置的編譯引導恢復到缺省狀態; |
|
|
#<num>; |
#10; //延遲10個時間單位 |
語句
說明
initial
塊語句:只執行一次,always循環執行;不可綜合;
作用:
產生激勵信號;
檢查輸出波形;
賦初值;
forever
//產生周期信號:
intial begin
clk = 0;
forever
#10 clk = ~clk; //時鐘信號
end
語句 |
說明 |
initial |
塊語句:只執行一次,always循環執行;不可綜合; |
作用: 產生激勵信號; 檢查輸出波形; 賦初值; |
|
forever |
//產生周期信號: intial begin clk = 0; forever #10 clk = ~clk; //時鐘信號 end |
1.6.4 系統任務和函數
條目
說明
$<標識符>
表示Verilg的系統任務和函數
$time
當前的仿真時間
$display
顯示信號值變化:只執行一次,打印當前時刻;
$display($time, “b% %b %b”, rst,clk,dout);
$monitor
監視信號值變化:所有過程時刻;
$monitor($time, “b% %b %b”, rst,clk,dout);
$stop
暫停仿真
$finish
結束仿真,釋放電腦資源;
1.7.1 組合邏輯電路
條目
說明
assign
assign add_cnt = flag==1; //用于簡單的組合邏輯電路;
always
always @(*)begin//統一采用“*”為敏感列表;
(=,if,case)語句;//只能使用“=”賦值
end
1.7.2 時序邏輯電路
計數器模板1
3段式模板
模板1
1
計數段
always @( posedge cllk or negedge rst_n) begin
if (!rst_n)
cnt <= 0; //初值規定為0
else if (add_cnt)begin//【位置1】
if(end_cnt)
cnt <= 0;
else
cnt <= cnt + 1;
end
end
2
加1條件
assingadd_cnt = d==1; //d==1: 什么時候開始數脈沖
3
結束條件
assing end_cnt = add_cnt&& cnt == X-1; // X:數多少個脈沖
計數器模板2
3段式模板
模板1
1
計數段
always @( posedge cllk or negedge rst_n) begin
if (!rst_n)
cnt <= 0; //初值規定為0
else if (add_cnt) begin//【位置1】
if(end_cnt)
cnt <= 0;
else
cnt <= cnt + 1;
end
else
cnt <= 0; //不連續,需要清0時,使用模板2;
end
2
加1條件
assingadd_cnt = d==1; //d==1: 什么時候開始數脈沖
3
結束條件
assing end_cnt = add_cnt&& cnt == X-1; // X:數多少個脈沖
模板4段式狀態機
段號
代碼
1
// 初始化,次態賦值給現態,明確當前狀態;
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
state_c <= S00;//初始狀態
else
state_c <= state_n;
end
2
always @( * ) begin //組合邏輯,描述狀態轉換目標
case(state_c)
S00: begin
if(s00_s20_start) // 條件名 S00->S20
state_n = S20;
else
state_n = state_c; // 方便拷貝
end
S20: begin
if(s20_s21_start)
state_n = S21;
else
state_n = state_c;
end
S21: begin
if(s21_s00_start)
state_n = S00;
else
state_n = state_c;
end
default: begin
state_n = S00;
end
endcase
end
3
//具體的轉換條件內容
assign s00_s20_start = state_c==S00&& (條件);
assign s20_s21_start = state_c==S20&& (條件);
assign s21_s20_start = state_c==S21&& (條件);
4
根據轉態設計輸出:
1個 always 設計1個輸出信號;
1.7.3 Testbench
框架
條目
內容
模塊名
`timescale 1 ns/1 ns
module testbench_name();
信號定義
reg clk ; //時鐘
reg rst_n; //復位
reg[3:0] din0 ; //uut的輸入信號 ,定義為reg型,在initial中
reg din1 ;
wire dout0;//uut的輸出信號, 定義為wire型
wire[4:0] dout1;
parameter CYCLE = 20; //參數定義,方便修改;
parameter RST_TIME = 3 ;
待測模塊例化
module_name uut( //統一采用名字關聯
.clk ( clk ),
.rst_n ( rst_n ),
.din0 ( din0 ),
.din1 ( din1 ),
.dout0 ( dout0 ),
.dout1 ( dout1 )
);
激勵產生
//復位,時鐘 ,等
顯示輸出結果
$display //類似printf;
復位
復位
initial begin
rst_n = 1;
#2;
rst_n = 0;
#(CYCLE*RST_TIME);
rst_n = 1;
end
仿真時鐘
仿真時鐘
initial begin
clk = 0;
forever
#(CYCLE/2)
clk=~clk;
end
激勵信號
激勵信號
initial begin
#1;//方便觀測
din1 = 0; //賦初值
#(10*CYCLE);
//開始賦值
end
以上就是本人總結的Verilog語法相關知識點,當然明德揚還有很多比較簡便的模板給我們使用,感興趣的朋友可以進入明德揚論壇(http://www.fpgabbs.cn/)進行更多FPGA 或者語法相關討論!
條目 |
說明 |
$<標識符> |
表示Verilg的系統任務和函數 |
$time |
當前的仿真時間 |
$display |
顯示信號值變化:只執行一次,打印當前時刻; $display($time, “b% %b %b”, rst,clk,dout); |
$monitor |
監視信號值變化:所有過程時刻; $monitor($time, “b% %b %b”, rst,clk,dout); |
$stop |
暫停仿真 |
$finish |
結束仿真,釋放電腦資源; |
條目 |
說明 |
assign |
assign add_cnt = flag==1; //用于簡單的組合邏輯電路; |
always |
always @(*)begin//統一采用“*”為敏感列表; (=,if,case)語句;//只能使用“=”賦值 end |
3段式模板 |
模板1 |
|
1 |
計數段 |
always @( posedge cllk or negedge rst_n) begin if (!rst_n) cnt <= 0; //初值規定為0 else if (add_cnt)begin//【位置1】 if(end_cnt) cnt <= 0; else cnt <= cnt + 1; end end |
2 |
加1條件 |
assingadd_cnt = d==1; //d==1: 什么時候開始數脈沖 |
3 |
結束條件 |
assing end_cnt = add_cnt&& cnt == X-1; // X:數多少個脈沖 |
計數器模板2
3段式模板 |
模板1 |
|
1 |
計數段 |
always @( posedge cllk or negedge rst_n) begin if (!rst_n) cnt <= 0; //初值規定為0 else if (add_cnt) begin//【位置1】 if(end_cnt) cnt <= 0; else cnt <= cnt + 1; end else cnt <= 0; //不連續,需要清0時,使用模板2; end |
2 |
加1條件 |
assingadd_cnt = d==1; //d==1: 什么時候開始數脈沖 |
3 |
結束條件 |
assing end_cnt = add_cnt&& cnt == X-1; // X:數多少個脈沖 |
模板4段式狀態機
段號
代碼
1
// 初始化,次態賦值給現態,明確當前狀態;
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
state_c <= S00;//初始狀態
else
state_c <= state_n;
end
2
always @( * ) begin //組合邏輯,描述狀態轉換目標
case(state_c)
S00: begin
if(s00_s20_start) // 條件名 S00->S20
state_n = S20;
else
state_n = state_c; // 方便拷貝
end
S20: begin
if(s20_s21_start)
state_n = S21;
else
state_n = state_c;
end
S21: begin
if(s21_s00_start)
state_n = S00;
else
state_n = state_c;
end
default: begin
state_n = S00;
end
endcase
end
3
//具體的轉換條件內容
assign s00_s20_start = state_c==S00&& (條件);
assign s20_s21_start = state_c==S20&& (條件);
assign s21_s20_start = state_c==S21&& (條件);
4
根據轉態設計輸出:
1個 always 設計1個輸出信號;
1.7.3 Testbench
框架
段號 |
代碼 |
1 |
// 初始化,次態賦值給現態,明確當前狀態; always @(posedge clk or negedge rst_n) begin if(!rst_n) state_c <= S00;//初始狀態 else state_c <= state_n; end |
2 |
always @( * ) begin //組合邏輯,描述狀態轉換目標 case(state_c) S00: begin if(s00_s20_start) // 條件名 S00->S20 state_n = S20; else state_n = state_c; // 方便拷貝 end S20: begin if(s20_s21_start) state_n = S21; else state_n = state_c; end S21: begin if(s21_s00_start) state_n = S00; else state_n = state_c; end default: begin state_n = S00; end endcase end |
3 |
//具體的轉換條件內容 assign s00_s20_start = state_c==S00&& (條件); assign s20_s21_start = state_c==S20&& (條件); assign s21_s20_start = state_c==S21&& (條件); |
4 |
根據轉態設計輸出: 1個 always 設計1個輸出信號; |
條目 |
內容 |
模塊名 |
`timescale 1 ns/1 ns module testbench_name(); |
信號定義 |
reg clk ; //時鐘 reg rst_n; //復位 reg[3:0] din0 ; //uut的輸入信號 ,定義為reg型,在initial中 reg din1 ; wire dout0;//uut的輸出信號, 定義為wire型 wire[4:0] dout1; parameter CYCLE = 20; //參數定義,方便修改; parameter RST_TIME = 3 ; |
待測模塊例化 |
module_name uut( //統一采用名字關聯 .clk ( clk ), .rst_n ( rst_n ), .din0 ( din0 ), .din1 ( din1 ), .dout0 ( dout0 ), .dout1 ( dout1 ) ); |
激勵產生 |
//復位,時鐘 ,等 |
顯示輸出結果 |
$display //類似printf; |
復位
復位
initial begin
rst_n = 1;
#2;
rst_n = 0;
#(CYCLE*RST_TIME);
rst_n = 1;
end
仿真時鐘
仿真時鐘
initial begin
clk = 0;
forever
#(CYCLE/2)
clk=~clk;
end
復位 |
initial begin rst_n = 1; #2; rst_n = 0; #(CYCLE*RST_TIME); rst_n = 1; end |
仿真時鐘 |
initial begin clk = 0; forever #(CYCLE/2) clk=~clk; end |
激勵信號
激勵信號
initial begin
#1;//方便觀測
din1 = 0; //賦初值
#(10*CYCLE);
//開始賦值
end
以上就是本人總結的Verilog語法相關知識點,當然明德揚還有很多比較簡便的模板給我們使用,感興趣的朋友可以進入明德揚論壇(http://www.fpgabbs.cn/)進行更多FPGA 或者語法相關討論!
激勵信號 |
initial begin #1;//方便觀測 din1 = 0; //賦初值 #(10*CYCLE); //開始賦值 end |