1.1 概述
條目 | 說明 |
分類 |
1>> 面向設計的語句; // 可綜合。 2>> 面向測試的語句; //testbench ,不可綜合。 |
特點 |
設計語句 assign , always ,模塊例化,都對應實際電路,並行執行。 |
構造 |
|
1.2 模塊 Module
條目 |
說明 |
模塊名(端口列表) |
整個電路的外特性,抽象為黑盒子; |
端口方向 |
input , output ; inout ; |
端口類型 |
wire , reg ; 端口類型是 wire 時可以省略。 例: input a ; // 端口方向為輸入,類型默認為 wire ; |
|
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 型數據 |
1.3.2 常量
類型 |
格式 |
說明 |
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 運算符
1.4.1 概述
運算符 |
說明 |
算術運算符 |
+ ( 加 ) , - (減), * (乘), / (除), % (取模); |
每個運算符在電路中都是個模塊,如加法器,減法器; !注意:除法,除 2^n ,是移位運算, 浮點運算就復雜了,因此浮點運算要專用除法器; |
|
關系運算符 |
>, <, >=, <= , == (相等), ! = (不相等); |
邏輯運算符 |
&& (邏輯與) . || (邏輯或) , ! (邏輯非); 條件判斷語句中,為避免歧義,邏輯運算符二邊推薦為 1bit ; |
位運算符 |
& (與), | (或), ~ (非) , ^ (異或) ; ~^ (同或); |
移位運算符 |
<< (左移), >> (右移); |
歸約操作 |
& , ~& , | , ~| , ^, ~^;//unary reduction ; |
條件運算符 |
?: |
拼接運算符 |
{} //{3{a[0]}}: 代表 3 根同樣的 a[0] 線, {a[0],a[0],a[0]} |
1.5 設計語句
1.5.1 assign (連續賦值)
實例 |
說明 |
assigny = ~ b ; assign out = a==1 && c==1 ; assign f = sel ? a : b ; |
>> 實現可以用布爾函數描述的組合邏輯電路; |
>>“=” 后面可以是任何布爾函數; >> 並行執行; |
|
典型錯誤 1 : assigna = b + a; |
避免出現反饋電路:變為了不可知時序邏輯電路;
|
1.5.2 always (過程塊)
a、賦值
賦值方式 |
說明 |
= ,阻塞賦值 |
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 塊內,阻塞賦值:並行執行; |
b、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 成對使用; |
c、case 語句
條目 |
說明 |
格式 |
case( 表達式 ) 常量表達式 1:begin 語句; end 常量表達式 2:begin 語句; end 常量表達式 3:begin 語句; end default : 語句; endcase |
特點 |
分支語句,各個分支條件相同;並行執行判斷; |
注意 |
default 語句不可省略; |
d、代碼 & 硬件
條目 |
說明 |
映射 |
賦值語句 -> 邏輯函數; // 加法器,減法器等; |
邊沿型條件分支 -> D 觸發器; |
|
條件分支 -> 多路選擇器; |
|
示例 |
|
1.5.3 模塊例化
a、作用
系統設計時,建議遵循以下設計原則:
b、常見的典型錯誤如下所示:
1.5.4 全加器
全加器頂層: w1 , w2 , w3 :模塊之間連線;
|
半加強: 2 種描述方法,如下:
|
描述方式
描述方式 |
說明 |
位置關聯 |
AND u1(a, b, and_out); |
名字關聯 |
AND u1(.a(a), .b(b), .o ( and_out ) ); // 推薦使用 |
1.6 測試語句
1.6.1 結構
Testbench |
|
|
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 語句
語句 |
說明 |
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.7.1 組合邏輯電路
條目 |
說明 |
assign |
assign add_cnt = flag==1; // 用於簡單的組合邏輯電路; |
always |
always @(*)begin// 統一采用“ *” 為敏感列表; ( =,if,case )語句; // 只能使用“ =” 賦值 end |
1.7.2 時序邏輯電路
a、計數器模板 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: 數多少個脈沖 |
b、計數器模板 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: 數多少個脈沖 |
c、 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
a、框架
條目 |
內容 |
模塊名 |
`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 ; |
b、復位
復位 |
initial begin rst_n = 1; #2; rst_n = 0; #(CYCLE*RST_TIME); rst_n = 1; end |
c、仿真時鍾
仿真時鍾 |
initial begin clk = 0; forever #(CYCLE/2) clk=~clk; end |
d、激勵信號
激勵信號 |
initial begin #1;// 方便觀測 din1 = 0; // 賦初值 #(10*CYCLE); // 開始賦值 end |
以上就是總結的 Verilog 語法相關知識點,轉自明德揚論壇