Verilog 预编译

2023-03-14,

Verilog 预编

Verilog 语言支持宏定义(`define),参数 parameter,局域参数(localparam)以及`include等内容。这些数据常量的支持极大方便数字系统设计、仿真与验证。这些参数是预编译的。

预编译

所谓预编译就是在系统编译之前,将定义的宏常量,参数等先对系统文件扫描一边,将文件中引用的宏和参数以实际值替代,对`include 文件的引用,将实际文件复制到对应位置,然后才对系统进行编译,这一点和具有编译运行的软件编译处理是一致的,如C语言,C++语言等。

宏定义
`define 关键字

宏定义的关键字是`define, 在预编译阶段,`define 用于文本替换,类似于 C 语言中的 #define。一旦 `define 指令被定义,其在整个翻译过程中都会有效。例如,在一个文件中定义:

`define DATA_DW 32 //含义是 DATA_DW=32, 在编写文件时使用`DATA_DW,在系统编译时,首先将所有`DATA_DW 出现的地方都替换成32,然后再编译。

则在另一个文件中也可以直接使用 `DATA_DW。当然这和编译工具的设定有关,建议一个文件中定义的宏只在该文件中使用。

使用宏的好处是,在全局中使用宏定义的常量,将来如果该常量有变化,直接改动宏定义就可以改动所有使用宏的地方。

宏定义也可以是一个表达式方式, 例如:

`define low_pos(w,b) ((w)*64 + (b)*8)

例:

设计文件 mul8.v

`define PW 8 module mul8 ( input [`PW-1:0] a, input [`PW-1:0] b, output [`PW*2-1:0] p ); assign p = a * b; endmodule
 

仿真文件 tb.v

`timescale 1 ns/1 ps

`define PW 8

module tb

(

 

);

 

parameter PERIOD = 10 ;

reg CLK;

initial

begin

CLK = 1'b0;

#(PERIOD/2);

 

forever

#(PERIOD/2) CLK = ~CLK;

end

 

reg [`PW-1:0] a, b;

 

wire [`PW*2-1:0] p;

 

initial

begin

a = `PW'b0;

b = `PW'b0;

end

 

always @(posedge CLK)

begin

a = a + 1;

 

if(a == 2**(`PW)-1 ) //对于求幂运算符**,只能是2的幂,指数部 //分必须是常量

b = b + 1;

end

 

mul8 mul8_dut

(

.a (a),

.b (b),

.p (p)

);

 

endmodule

`undef 关键字

利用`undef 关键字可以中止当前宏常量的定义。

如: `undef PW

文件在这条语句之后 就不能再以`PW 替代8 使用。

`ifdef, `ifndef, `elsif, `else, `endif

`elsif, `else 编译指令对于 `ifdef 指令是可选的,即可以只使用 `ifdef 和 `endif 组成一次条件编译指令块。

例:缺省对32位数据处理,如果定义宏,则按宏定义处理

`ifdef DATA_DW

reg [`DATA_DW-1:0] data_a;

reg [`DATA_DW-1:0] data_b;

reg [`DATA_DW-1:0] data_c;

`else

reg [31:0] data_a;

reg [31:0] data_b;

reg [31:0] data_c;

`endif

注: 宏一般在定义时大小写字符都可以使用,而且大小写是区分的,也就是大写字符定义的宏与小写字符定义宏虽然只有大小写之分,却代表了不同的宏

如:

`define data_w 8 与`define DATA_W 32 定义的宏,可以分别使用,互不冲突。一般习惯宏都是用大写字母。

参数 parameter与局部参数localparam

parameter 与localparam都可以定义参数常量,但使用范围不同:

localparam定义的参数仅限于本module内部使用,模块例化不可调用,相当于局部常量。状态机状态常量定义,而且只能在定义的位置之后使用。

parameter定义的参数不仅能在本文件中使用,还能利用module 例化后起到参数传递的作用。parameter经常在module接口,以及在设计文件中多处使用特定常数的地方使用。

 

举例:

设计文件 para_fadder.v

module para_fadder

#(

parameter WDTH = 4

)

(

input ci,

input [WDTH-1:0] a,

input [WDTH-1:0] b,

output [WDTH-1:0] sum,

output co

);

 

assign {co, sum} = a + b + ci;

 

endmodule

Testbench 文件 tb.v

`timescale 1ns/1ps

 

module tb

(

);

 

parameter WDTH = 16;

 

reg ci;

reg [WDTH-1:0] a, b;

 

wire [WDTH-1:0] sum;

wire co;

 

initial

begin

a ='b0;

b ='b0;

ci = 0;

 

#10

 

a ='d100;

b ='d33;

ci = 0;

#10

 

a ='d101;

b ='d37;

ci = 1;

end

 
 
 

para_fadder

#(

.WDTH(WDTH)

)

para_fadder_dut

(

.ci (ci),

.a (a),

.b (b),

.sum (sum),

.co (co)

);

 

endmodule

Modelsim仿真波形

 

 

 

说明: 在设计文件中定义了 参数 WDTH=4,而在例化中传递的参数为16,那么最终在设计文件中的参数的具体数值由传递值决定,本例中WDTH的最终为16,最终例化了16位全加器。如果在例化中没有给参数传递值,则WDTH=4变成缺省值,即例化4位全加器。如例化如下:

para_fadder para_fadder_dut ( .ci (ci), .a (a), .b (b), .sum (sum), .co (co) );

将例化成4位全加器。

 

module中 parameter 的格式如下:

 

设计文件

module para_fadder #( parameter WDTH = 4, parameter WDTH1 = 4 //最后一个参数没有分隔符 )
 

多个参数采用逗号 “,”隔开,最后一个参数没有分隔符 。

例化端类似的格式:

 
para_fadder #( .WDTH (WDTH), .WDTH1 (WDTH1) )
 

如果只有一个参数,则为

para_fadder #( .WDTH(WDTH) )
 

Verilog 预编译的相关教程结束。

《Verilog 预编译.doc》

下载本文的Word格式文档,以方便收藏与打印。