赞
踩
当一个模块被另一个模块引用例化时,高层模块可以对低层模块的参数值进行改写。这样就允许在编译时将不同的参数传递给多个相同名字的模块,而不用单独为只有参数不同的多个模块再新建文件。
参数覆盖有 2 种方式:1)使用关键字 defparam,2)例化时修改:带参数值模块例化。
使用参数的方式定义常量有很多好处,如:
我们在RTL代码中实例化该模块时,如果需要两个不同计数值的计数器我们不必设计两个模块,而是直接修改参数的值即可;
另一个好处是在编写Testbench进行仿真时我们也需要实例化该模块,但是我们需要仿真至少0.5s的时间才能够看出到led_out效果,这会让仿真时间很长,也会导致产生的仿真文件很大,所以我们可以通过直接修改参数的方式来缩短仿真的时间而看到相同的效果,且不会影响到RTL代码模块中的实际值,因为parameter定义的是局部参数,所以只在本模块中有效。
为了更好的区分,参数名我们习惯上都是大写。
格式:
#(
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灯
);
格式:
parameter 参数名 = XX;
不同参数定义用分号结束语句
举例:
//=========================< Parameter >==============================
parameter CNT_MAX = 25'd100 ;
parameter CNT_MAX_5 = CNT_MAX - 5 ;
格式:
#(
.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
);
也可以去掉参数名,按顺序进行参数例化(但是不建议哦,不方便阅读):
#(
25'd24,
25'd19
)
格式:
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
);
如果是需要对多层级的子模块进行参数修改,可以使用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
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
);
仿真时参数修改,在模块中使用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
格式:
defparam U_TOP.u_dived_clk.DIV_FREQUENCY =20;
defparam U_TOP.u_dived_clk.PERIOD_WIDTH_MAX =5;
defparam 当前例化模块名.子例化模块名.子子例化模块名.参数 = 数值;
中间用.分隔模块,不同修改参数用分号结束语句
注意是用例化模块名而不是用子模块名,两者区别如下:
将需要修改的参数统一放置在一文件中用`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
模块C(只定义参数):
`define BASE_RATE 1000
`define INTERVAL_CYCLE 200
`define后面没有分号
`include包含文件的格式为:`include+“文件路径” 后面没有分号(由此可见define结合include可以实现跨文件传递参数)
其中的文件路径的格式(注意此处的斜杠/的方向):
可使用绝对路径 如:`include “F:/project/rtl/C.v”
可使用相对路径如:
需要包含的文件在本层级上一级的para文件夹中,则:`include “../para/C.v”
需要包含的文件在本层级下一级的para文件夹中,则:`include “para/C.v” 或是 `include “./para/C.v”
其中./表示当前目录,../表示上一层目录
参数定义 | 参数修改 |
---|---|
模块名后定义参数 | 例化时修改 |
模块名后定义参数 | defparam修改 |
parameter定义参数 | 例化时修改 |
parameter定义参数 | defparam修改 |
如果rtl模块中既有模块名后定义参数又有parameter定义参数,用defparam修改会报错,用例化时修改不报错。具体看建议与区别部分(4)
使用建议用模块名后定义参数与例化时修改这一对应方案。
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灯
);
例化代码中:
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
);
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
仿真部分:
`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
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。