以反引号 ` 開始的某些辨別符是 Verilog 系統編譯指令。
編譯指令為 Verilog 代碼的撰寫、編譯、調試等提供了極大的便利。
下面介紹下完整的 8 種編譯指令,其中前 4 種使用頻率較高。
`define, `undef
在編譯階段,`define 用于文本替換,類似于 C 語言中的 #define。
一旦 `define 指令被編譯,其在整個編譯過程中都會有效。例如,在一個檔案中定義:
`define DATA_DW 32
則在另一個檔案中也可以直接使用 DATA_DW。
`define S $stop;
//用`S來代替系統函數$stop; (包括分号)
`define WORD_DEF reg [31:0]
//可以用`WORD_DEF來聲明32bit寄存器變量
`undef 用來取消之前的宏定義,例如:
`define DATA_DW 32
……
reg [DATA_DW-1:0] data_in ;
……
`undef DATA_DW
`ifdef, `ifndef, `elsif, `else, `endif
這些屬于條件編譯指令。例如下面的例子中,如果定義了 MCU51,則使用第一種參數說明;如果沒有定義 MCU、定義了 WINDOW,則使用第二種參數說明;如果 2 個都沒有定義,則使用第三種參數說明。
`ifdef MCU51
parameter DATA_DW = 8 ;
`elsif WINDOW
parameter DATA_DW = 64 ;
`else
parameter DATA_DW = 32 ;
`endif
`elsif, `else 編譯指令對于 `ifdef 指令是可選的,即可以隻有 `ifdef 和 `endif 組成一次條件編譯指令塊。
當然,也可用 `ifndef 來設定條件編譯,表示如果沒有相關的宏定義,則執行相關語句。
下面例子中,如果定義了 WINDOW,則使用第二種參數說明。如果沒有定義 WINDOW,則使用第一種參數說明。
`ifndef WINDOW
parameter DATA_DW = 32 ;
`else
parameter DATA_DW = 64 ;
`endif
`include
使用 `include 可以在編譯時将一個 Verilog 檔案内嵌到另一個 Verilog 檔案中,作用類似于 C 語言中的 #include 結構。該指令通常用于将全局或公用的頭檔案包含在設計檔案裡。
檔案路徑既可以使用相對路徑,也可以使用絕對路徑。
`include "../../param.v"
`include "header.v"
`timescale
在 Verilog 模型中,時延有具體的機關時間表述,并用 `timescale 編譯指令将時間機關與實際時間相關聯。
該指令用于定義時延、仿真的機關和精度,格式為:
time_unit 表示時間機關,time_precision 表示時間精度,它們均是由數字以及機關 s(秒),ms(毫秒),us(微妙),ns(納秒),ps(皮秒)和 fs(飛秒)組成。時間精度可以和時間機關一樣,但是時間精度大小不能超過時間機關大小,例如下面例子中,輸出端 Z 會延遲 5.21ns 輸出 A&B 的結果。
`timescale 1ns/100ps //時間機關為1ns,精度為100ps,合法
//`timescale 100ps/1ns //不合法
module AndFunc(Z, A, B);
output Z;
input A, B ;
assign #5.207 Z = A & B
endmodule
在編譯過程中,`timescale 指令會影響後面所有子產品中的時延值,直至遇到另一個 `timescale 指令或 `resetall 指令。
由于在 Verilog 中沒有預設的 `timescale,如果沒有指定 `timescale,Verilog 子產品就有會繼承前面編譯子產品的 `timescale 參數。有可能導緻設計出錯。
如果一個設計中的多個子產品都帶有 `timescale 時,模拟器總是定位在所有子產品的最小時延精度上,并且所有時延都相應地換算為最小時延精度,時延機關并不受影響。例如:
`timescale 10ns/1ns
module test;
reg A, B ;
wire OUTZ ;
initial begin
A = 1;
B = 0;
# 1.28 B = 1;
# 3.1 A = 0;
end
AndFunc u_and(OUTZ, A, B) ;
endmodule
在子產品 AndFunc 中,5.207 對應 5.21ns。
在子產品 test 中,1.28 對應 13ns,3.1 對應 31ns。
但是,當仿真 test 時,由于 AndFunc 中的最小精度為 100ps,是以 test 中的時延精度将進行重新調整。13ns 将對應 130*100ps,31ns 将對應 310*100ps。仿真時,時延精度也會使用 100ps。仿真時間機關大小沒有影響。
如果有并行子子產品,子子產品間的 `timescale 并不會互相影響。
例如在子產品 test 中再例化一個子子產品 OrFunc。仿真 test 時,OrFunc 中的 #5.207 延時依然對應 52ns。
//子子產品:
`timescale 10ns/1ns //時間機關為1ns,精度為100ps,合法
module OrFunc(Z, A, B);
output Z;
input A, B ;
assign #5.207 Z = A | B
endmodule
//頂層子產品:
`timescale 10ns/1ns
module test;
reg A, B ;
wire OUTZ ;
wire OUTX ;
initial begin
A = 1;
B = 0;
# 1.28 B = 1;
# 3.1 A = 0;
end
AndFunc u_and(OUTZ, A, B) ;
OrFunc u_and(OUTX, A, B) ;
endmodule
此例中,仿真 test 時,OrFunc 中的 #5.207 延時依然對應 52ns。
`timescale 的時間精度設定是會影響仿真時間的。時間精度越小,仿真時占用記憶體越多,實際使用的仿真時間就越長。是以如果沒有必要,應盡量将時間精度設定的大一些。
`default_nettype
該指令用于為隐式的線網變量指定為線網類型,即将沒有被聲明的連線定義為線網類型。
該執行個體定義的預設的線網為線與類型。是以,如果在此指令後面的任何子產品中的連線沒有說明,那麼該線網被假定為線與類型。
該執行個體定義後,将不再自動産生 wire 型變量。
例如下面第一種寫法編譯時不會報 Error,第二種寫法編譯将不會通過。
//Z1 無定義就使用,系統預設Z1為wire型變量,有 Warning 無 Error
module test_and(
input A,
input B,
output Z);
assign Z1 = A & B ;
endmodule
//Z1無定義就使用,由于編譯指令的存在,系統會報Error,進而檢查出書寫錯誤
`default_nettype none
module test_and(
input A,
input B,
output Z);
assign Z1 = A & B ;
endmodule
`resetall
該編譯器指令将所有的編譯指令重新設定為預設值。
`resetall 可以使得預設連線類型為線網類型。
`celldefine, `endcelldefine
`celldefine
module (
input clk,
input rst,
output clk_pll,
output flag);
……
endmodule
`endcelldefine
`unconnected_drive, `nounconnected_drive
`unconnected_drive pull1
. . .
/ *在這兩個程式指令間的所有未連接配接的輸入端口為正偏電路狀态(連接配接到高電平) * /
`nounconnected_drive
`unconnected_drive pull0
. . .
/ *在這兩個程式指令間的所有未連接配接的輸入端口為反偏電路狀态(連接配接到低電平) * /
`nounconnected_drive