当前位置:   article > 正文

Verilog参数定义与例化模块中的参数修改_verilog参数位置对例化影响

verilog参数位置对例化影响

定义参数的优势

当一个模块被另一个模块引用例化时,高层模块可以对低层模块的参数值进行改写。这样就允许在编译时将不同的参数传递给多个相同名字的模块,而不用单独为只有参数不同的多个模块再新建文件。

参数覆盖有 2 种方式:1)使用关键字 defparam,2)例化时修改:带参数值模块例化。

使用参数的方式定义常量有很多好处,如:

  1. 我们在RTL代码中实例化该模块时,如果需要两个不同计数值的计数器我们不必设计两个模块,而是直接修改参数的值即可

  2. 另一个好处是在编写Testbench进行仿真时我们也需要实例化该模块,但是我们需要仿真至少0.5s的时间才能够看出到led_out效果,这会让仿真时间很长,也会导致产生的仿真文件很大,所以我们可以通过直接修改参数的方式来缩短仿真的时间而看到相同的效果,且不会影响到RTL代码模块中的实际值,因为parameter定义的是局部参数,所以只在本模块中有效。

为了更好的区分,参数名我们习惯上都是大写。

rtl模块中的参数定义

模块名后定义参数

格式:

#(
parameter CNT_MAX = 25’d100,
parameter CNT_MAX_5 = CNT_MAX - 5
)


#+()
()内用parameter 参数名 = XX
()内的参数间用逗号分隔,最后一个参数后没有逗号

举例:

module test
#(
parameter CNT_MAX = 25'd100,
parameter CNT_MAX_5 = CNT_MAX - 5
 )
 (
 input wire sys_clk , //系统时钟50MHz
 input wire sys_rst_n , //全局复位

 output reg led_out //输出控制led灯
 );
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

parameter定义参数

格式:

parameter 参数名 = XX;

不同参数定义用分号结束语句

举例:

//=========================< Parameter >==============================
	parameter 				CNT_MAX		=	25'd100		    	;
	parameter 				CNT_MAX_5 	= 	CNT_MAX - 5			;
  • 1
  • 2
  • 3

例化模块中的参数修改

例化时修改

格式:

#(
.CNT_MAX (25’d24 ),
.CNT_MAX_5(25’d19)
)


#+()
()内用 .参数名(修改后的数值)
()内的参数间用逗号分隔,最后一个参数后没有逗号

举例:

test
 #(
 .CNT_MAX (25'd24 ),
 .CNT_MAX_5(25'd19)
 )
 counter_inst(
 .sys_clk (sys_clk ), //input sys_clk
 .sys_rst_n (sys_rst_n ), //input sys_rst_n

 .led_out (led_out ) //output led_out
 );
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

也可以去掉参数名,按顺序进行参数例化(但是不建议哦,不方便阅读):

#(
 25'd24,
 25'd19
 )
  • 1
  • 2
  • 3
  • 4

defparam修改

格式:

defparam counter_inst.CNT_MAX = 25’d24 ;
defparam counter_inst.CNT_MAX_5 = 25’d19 ;


defparam 模块例化的参数名.模块中的参数 = 数值;
不同修改参数用分号结束语句

举例:

//=========================< Parameter >==============================
defparam 			counter_inst.CNT_MAX	=		25'd24	    	;
defparam 			counter_inst.CNT_MAX_5	=		25'd19			;
	
 test counter_inst(
	.sys_clk 	(sys_clk 	), //input sys_clk
	.sys_rst_n 	(sys_rst_n 	), //input sys_rst_n
	
	.led_out 	(led_out 	) //output led_out
 );
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

例化时对子模块中的参数修改

defparam层次化引用修改

如果是需要对多层级的子模块进行参数修改,可以使用defparam进行修改。

例如:TOP模块例化有dived_clk与clk_period两个模块,其中dived_clk模块内部的两个参数需要在仿真时修改。
TOP模块:

module TOP(
	input 	wire 	rst_n 		,
	input 	wire 	clk 		,
	
	output	wire	dived_clk	,
	output	wire	clk_flag1	,
	output	wire	clk_flag2
);

dived_clk u_dived_clk(
	.rst_n 		(rst_n 		),
	.clk 		(clk 		),
	
	.dived_clk  (dived_clk)
);

clk_period u_clk_period(
	.rst_n 		(rst_n 		),
	.clk 		(clk 		),
	.dived_clk	(dived_clk	),
	
	.clk_flag1	(clk_flag1	),
	.clk_flag2  (clk_flag2	)
);
endmodule
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

dived_clk模块参数部分:

module dived_clk
#(
	parameter 				DIV_FREQUENCY		=	4,//分频数(只允许偶分频),dived_clk周期为DIV_FREQUENCY*clk的周期
	parameter 				PERIOD_WIDTH_MAX	=	2//(DIV_FREQUENCY-1)对应的二进制位宽
)
(
	input 	wire rst_n 	,
	input 	wire clk 	,
	
	output  reg  dived_clk
);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

仿真时参数修改,在模块中使用defparam进行修改:

module tb_clk_period();
	
XXX;//省略部分
XXX;//省略部分
    
TOP U_TOP(
	.rst_n 		(i_rst_n 	),
	.clk 		(i_clk 		),
	
	.dived_clk	(dived_clk	),
	.clk_flag1	(clk_flag1	),
	.clk_flag2  (clk_flag2	)
);

	defparam U_TOP.u_dived_clk.DIV_FREQUENCY   =20;
	defparam U_TOP.u_dived_clk.PERIOD_WIDTH_MAX =5;

endmodule
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

注意事项

格式:

defparam U_TOP.u_dived_clk.DIV_FREQUENCY =20;
defparam U_TOP.u_dived_clk.PERIOD_WIDTH_MAX =5;


defparam 当前例化模块名.子例化模块名.子子例化模块名.参数 = 数值;
中间用.分隔模块,不同修改参数用分号结束语句

注意是用例化模块名而不是用子模块名,两者区别如下:

在这里插入图片描述

`include修改

将需要修改的参数统一放置在一文件中用`define定义。再其他模块中引用时使用`include包含该模块后使用 `参数 的格式进行引用;修改参数时只需修改define文件的参数值即可

例如:A模块中对B模块进行例化时需要修改参数,我们引用C模块定义的参数进行修改。

模块A:

module A
(
    input           xx,
    input           xx,
    output[3:0]     xx 
);

`include "C.v"
B 
#(  .C_BASE_RATE    ( `BASE_RATE        ), //引用C中定义的参数
    .C_INTERVAL     ( `INTERVAL_CYCLE   ), //引用C中定义的参数
    .C_DAT_W        ( 16    			)
)
u_B
(
    .i_rst_n        ( i_rst_n       ),
    .i_clk          ( i_clk         ),
    .XXX			(XXX			),
	.XXX			(XXX			),
    .flag   		( flag  		)
);

endmodule
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

模块C(只定义参数):

`define     BASE_RATE       1000
`define     INTERVAL_CYCLE  200
  • 1
  • 2

注意事项

`define后面没有分号

`include包含文件的格式为:`include+“文件路径” 后面没有分号(由此可见define结合include可以实现跨文件传递参数)

其中的文件路径的格式(注意此处的斜杠/的方向):

  1. 可使用绝对路径 如:`include “F:/project/rtl/C.v”

  2. 可使用相对路径如:

    需要包含的文件在本层级上一级的para文件夹中,则:`include “../para/C.v”

    需要包含的文件在本层级下一级的para文件夹中,则:`include “para/C.v” 或是 `include “./para/C.v”

    其中./表示当前目录,../表示上一层目录

总结与说明

  1. 参数定义(两种方法)和例化模块中的参数修改(两种方法)可以选择使用,共四种对应写法(此处未加上`include方式)。
参数定义参数修改
模块名后定义参数例化时修改
模块名后定义参数defparam修改
parameter定义参数例化时修改
parameter定义参数defparam修改
  1. 如果rtl模块中既有模块名后定义参数又有parameter定义参数,用defparam修改会报错,用例化时修改不报错。具体看建议与区别部分(4)

  2. 使用建议用模块名后定义参数例化时修改这一对应方案。

rtl中:

module test
#(
parameter CNT_MAX = 25'd100,
parameter CNT_MAX_5 = CNT_MAX - 5
 )
 (
 input wire sys_clk , //系统时钟50MHz
 input wire sys_rst_n , //全局复位

 output reg led_out //输出控制led灯
 );
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

例化代码中:

test
 #(
 .CNT_MAX (25'd24 ),
 .CNT_MAX_5(25'd19)
 )
 counter_inst(
 .sys_clk (sys_clk ), //input sys_clk
 .sys_rst_n (sys_rst_n ), //input sys_rst_n

 .led_out (led_out ) //output led_out
 );
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

附录:测试代码

rtl部分:

module test
#(
parameter CNT_MAX = 25'd100,
parameter CNT_MAX_5 = CNT_MAX - 5
 )
 (
 input wire sys_clk , //系统时钟50MHz
 input wire sys_rst_n , //全局复位

 output reg led_out //输出控制led灯
 );

/* 	//=========================< Parameter >==============================
	parameter 				CNT_MAX		=	25'd100		    	;
	parameter 				CNT_MAX_5 	= 	CNT_MAX - 5			;
	 */
 reg [24:0] cnt; 

 //cnt:计数器计数,当计数到CNT_MAX的值时清零
 always@(posedge sys_clk or negedge sys_rst_n)
 if(sys_rst_n == 1'b0)
 cnt <= 25'b0;
 else if(cnt == CNT_MAX)
 cnt <= 25'b0;
 else
 cnt <= cnt + 1'b1;

 //led_out:输出控制一个LED灯,每当计数满标志信号有效时取反
 always@(posedge sys_clk or negedge sys_rst_n)
 if(sys_rst_n == 1'b0)
 led_out <= 1'b0;
 else if(cnt == CNT_MAX_5)
 led_out <= ~led_out;

 endmodule
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35

仿真部分:

`timescale 1ns/1ns
module tb_test();

//reg define
reg sys_clk;
reg sys_rst_n;

//wire define
wire led_out;

 //初始化输入信号
 initial begin
 sys_clk = 1'b1;
 sys_rst_n <= 1'b0;
 #20
 sys_rst_n <= 1'b1;
 end

 //sys_clk:每10ns电平翻转一次,产生一个50MHz的时钟信号
 always #10 sys_clk = ~sys_clk;
 
/* 	//=========================< Parameter >==============================
	defparam 			counter_inst.CNT_MAX	=		25'd25	    	;
	defparam 			counter_inst.CNT_MAX_5	=		25'd20			;
 */

 //---------------------flip_flop_inst----------------------
 test
/*  #(
 25'd24,
 25'd19
 )
  */
 #(
 .CNT_MAX (25'd23 ),
 .CNT_MAX_5(25'd20)//实例化带参数的模块时要注意格式,当我们想要修改常数在
 //当前模块的值时,直接在实例化参数名后面的括号内修改即可
 )
 counter_inst(
	.sys_clk 	(sys_clk 	), //input sys_clk
	.sys_rst_n 	(sys_rst_n 	), //input sys_rst_n
	
	.led_out 	(led_out 	) //output led_out
 );

 endmodule
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Monodyee/article/detail/462697
推荐阅读
相关标签
  

闽ICP备14008679号