宏定義 `define
用一個指定的標識符(即名字)來代表一個字符串,它的一般形式為:
`define 標識符(宏名) 字符串(宏內容)
如:`define signal string
它的作用是指定用標識符signal來代替string這個字符串,在編譯預處理時,把程序中在該命令以后所有的signal都替換成string。這種方法使用戶能以一個簡單的名字代替一個長的字符串,也可以用一個有含義的名字來代替沒有含義的數字和符號,因此把這個標識符(名字)稱為“宏名”,在編譯預處理時將宏名替換成字符串的過程稱為“宏展開”。`define是宏定義命令。
[例1]:`define WORDSIZE 8
module
reg[1:`WORDSIZE] data; //這相當於定義 reg[1:8] data;
關於宏定義的八點說明:
1) 宏名可以用大寫字母表示,也可以用小寫字母表示。建議使用大寫字母,以與變量名相區別。
2) `define命令可以出現在模塊定義里面,也可以出現在模塊定義外面。宏名的有效范圍為定義命令之后到原文件結束。通常,`define命令寫在模塊定義的外面,作為程序的一部分,在此程序內有效。
3) 在引用已定義的宏名時,必須在宏名的前面加上符號“`”,表示該名字是一個經過宏定義的名字。
4) 使用宏名代替一個字符串,可以減少程序中重復書寫某些字符串的工作量。而且記住一個宏名要比記住一個無規律的字符串容易,這樣在讀程序時能立即知道它的含義,當需要改變某一個變量時,可以只改變 `define命令行,一改全改。如例1中,先定義WORDSIZE代表常量8,這時寄存器data是一個8位的寄存器。如果需要改變寄存器的大小,只需把該命令行改為:`define WORDSIZE 16。這樣寄存器data則變為一個16位的寄存器。由此可見使用宏定義,可以提高程序的可移植性和可讀性。
5) 宏定義是用宏名代替一個字符串,也就是作簡單的置換,不作語法檢查。預處理時照樣代入,不管含義是否正確。只有在編譯已被宏展開后的源程序時才報錯。
6) 宏定義不是Verilog HDL語句,不必在行末加分號。如果加了分號會連分號一起進行置換。如:
[例2]:module test;
reg a, b, c, d, e, out;
`define expression a+b+c+d;
assign out = `expression + e;
...
endmodule
經過宏展開以后,該語句為:
assign out = a+b+c+d;+e;
顯然出現語法錯誤。
7) 在進行宏定義時,可以引用已定義的宏名,可以層層置換。如:
[例3]:module test;
reg a, b, c;
wire out;
`define aa a + b
`define cc c + `aa
assign out = `cc;
endmodule
這樣經過宏展開以后,assign語句為
assign out = c + a + b;
8) 宏名和宏內容必須在同一行中進行聲明。如果在宏內容中包含有注釋行,注釋行不會作為被置換的內容。如:
[例4]: module
`define typ_nand nand #5 //define a nand with typical delay
`typ_nand g121(q21,n10,n11);
………
endmodule
經過宏展開以后,該語句為:
nand #5 g121(q21,n10,n11);
宏內容可以是空格,在這種情況下,宏內容被定義為空的。當引用這個宏名時,不會有內容被置換。
注意:組成宏內容的字符串不能夠被以下的語句記號分隔開的。
- 注釋行
- 數字
- 字符串
- 確認符
- 關鍵詞
- 雙目和三目字符運算符
如下面的宏定義聲明和引用是非法的。
`define first_half "start of string
$display(`first_half end of string");
注意在使用宏定義時要注意以下情況:
1) 對於某些 EDA軟件,在編寫源程序時,如使用和預處理命令名相同的宏名會發生沖突,因此建議不要使用和預處理命令名相同的宏名。
2) 宏名可以是普通的標識符(變量名)。例如signal_name 和 'signal_name的意義是不同的。但是這樣容易引起混淆,建議不要這樣使用。
