3.9.1.宏定义 `define
用一个指定的标识符(即名字)来代表一个字符串,它的一般形式为:
`define 标识符(宏名) 字符串(宏内容)
如:`define signal string
它的作用是指定用标识符signal来代替string这个字符串,在编译预处理时,把程序中在该命令以后
所有的signal都替换成string。这种方法使用户能以一个简单的名字代替一个长的字符串,也可以用
一个有含义的名字来代替没有含义的数字和符号,因此把这个标识符(名字)称为“宏名”,在编译预
处理时将宏名替换成字符串的过程称为“宏展开”。`define是宏定义命令。
[例1]:`define WORDSIZE 8
module
reg[1:`WORDSIZE] data; //这相当于定义 reg[1:8] data;
关于宏定义的八点说明:
1) 宏名可以用大写字母表示,也可以用小写字母表示。建议使用大写字母,以与变量名相
区别。
57
第三章 Verilog HDL 基本语法
--------------------------------------------------------------------------------------------------------------------------------------------
------
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);
宏内容可以是空格,在这种情况下,宏内容被定义为空的。当引用这个宏名时,不会有内容被置换。
注意:组成宏内容的字符串不能够被以下的语句记号分隔开的。
• 注释行
58
第三章 Verilog HDL 基本语法
--------------------------------------------------------------------------------------------------------------------------------------------
------
• 数字
• 字符串
• 确认符
• 关键词
• 双目和三目字符运算符
如下面的宏定义声明和引用是非法的。
`define first_half "start of string
$display(`first_half end of string");
注意在使用宏定义时要注意以下情况:
1) 对于某些 EDA软件,在编写源程序时,如使用和预处理命令名相同的宏名会发生冲突,因
此建议不要使用和预处理命令名相同的宏名。
2) 宏名可以是普通的标识符(变量名)。例如signal_name 和 'signal_name的意义是不同的。
但是这样容易引起混淆,建议不要这样使用。
3.9.2.“文件包含”处理`include
所谓“文件包含”处理是一个源文件可以将另外一个源文件的全部内容包含进来,即将另外的文件包
含到本文件之中。Verilog HDL语言提供了`include命令用来实现“文件包含”的操作。其一般形式
为:
`include “文件名”
File1.v File2.v File1.v
`include File2.v”
A B
B
A
包 含
(a) (b) (c)
图 3-9-2
图3-9-2表示“文件包含”的含意。图3-9-2(a)为文件File1.v,它有一个`include "File2.v"命令,
然后还有其它的内容(以A表示)。图3-9-2(b)为另一个文件File2.v,文件的内容以B表示。在编译预
处理时,要对`include命令进行“文件包含”预处理:将File2.v的全部内容复制插入到 `include
"File2.v"命令出现的地方,即File2.v 被包含到File1.v中,得到图3-9-2(c)所示的结果。在接着
往下进行的编译中,将“包含”以后的File1.v作为一个源文件单位进行编译。
“文件包含”命令是很有用的,它可以节省程序设计人员的重复劳动。可以将一些常用的宏定义命令
或任务(task)组成一个文件,然后用`include命令将这些宏定义包含到自己所写的源文件中,相当于
59
第三章 Verilog HDL 基本语法
--------------------------------------------------------------------------------------------------------------------------------------------
------
工业上的标准元件拿来使用。另外在编写Verilog HDL源文件时,一个源文件可能经常要用到另外几
个源文件中的模块,遇到这种情况即可用`include命令将所需模块的源文件包含进来。
[例1]:
(1)文件aaa.v
module aaa(a,b,out);
input a, b;
output out;
wire out;
assign out = a^b;
endmodule
(2)文件 bbb.v
`include "aaa.v"
module bbb(c,d,e,out);
input c,d,e;
output out;
wire out_a;
wire out;
aaa aaa(.a(c),.b(d),.out(out_a));
assign out=e&out_a;
endmodule
在上面的例子中,文件bbb.v用到了文件aaa.v中的模块aaa的实例器件,通过“文件包含”处理来调
用。模块aaa实际上是作为模块bbb的子模块来被调用的。在经过编译预处理后,文件bbb.v实际相当
于下面的程序文件bbb.v:
module aaa(a,b,out);
input a, b;
output out;
wire out;
assign out = a ^ b;
endmodule
module bbb( c, d, e, out);
input c, d, e;
output out;
wire out_a;
wire out;
aaa aaa(.a(c),.b(d),.out(out_a));
assign out= e & out_a;
endmodule
关于“文件包含”处理的四点说明:
1) 一个`include命令只能指定一个被包含的文件,如果要包含n个文件,要用n个`include
命令。注意下面的写法是非法的`include"aaa.v""bbb.v"
2) `include命令可以出现在Verilog HDL源程序的任何地方,被包含文件名可以是相对路径
名,也可以是绝对路径名。例如:'include"parts/count.v"
3) 可以将多个`include命令写在一行,在`include命令行,只可以出空格和注释行。例如
下面的写法是合法的。
'include "fileB" 'include "fileC" //including fileB and fileC
60
第三章 Verilog HDL 基本语法
--------------------------------------------------------------------------------------------------------------------------------------------
------
4) 如果文件1包含文件2,而文件2要用到文件3的内容,则可以在文件1用两个`include命令
分别包含文件2和文件3,而且文件3应出现在文件2之前。例如在下面的例子中,即在file1.v
中定义:
`include"file3.v"
`include"file2.v"
module test(a,b,out);
input[1:`size2] a, b;
output[1:`size2] out;
wire[1:`size2] out;
assign out= a+b;
endmodule
file2.v的内容为:
`define size2 `size1+1
.
.
.
file3.v的内容为:
`define size1 4
.
.
.
这样,file1.v和file2.v都可以用到file3.v的内容。在file2.v中不必再用 `include "file3.v"
了。
5) 在一个被包含文件中又可以包含另一个被包含文件,即文件包含是可以嵌套的。例如
上面的问题也可以这样处理,见图3-9-3.
( 不 包 含 `include 命 令 )
……….
………..
…………
………..
file1.v file2.v file3.v
`include file2.v
…….
……..
…………
`include file3.v
……
…….
…….
图 3-9-3
它的作用和图3-9-4的作用是相同的。
61
第三章 Verilog HDL 基本语法
--------------------------------------------------------------------------------------------------------------------------------------------
------
file1.v file2.v file3.v
`include file3.v
`include file2.v.
……….
……….
……….
(不 包 含 `include 命 令)
…….
…….
…….
(不 包 含 `include 命 令 )
………
………..
………..
图3-9-4 |