文章目录
参数方式定义参数的优势
当一个模块被另一个模块引用例化时,高层模块可以对低层模块的参数值进行改写。这样就允许在编译时将不同的参数传递给多个相同名字的模块,而不用单独为只有参数不同的多个模块再新建文件。
参数覆盖有 2 种方式:1)使用关键字 defparam,2)例化时修改:带参数值模块例化。
使用参数的方式定义常量有很多好处,如:
-
我们在RTL代码中实例化该模块时,如果需要两个不同计数值的计数器我们不必设计两个模块,而是直接修改参数的值即可;
-
另一个好处是在编写Testbench进行仿真时我们也需要实例化该模块,但是我们需要仿真至少0.5s的时间才能够看出到led_out效果,这会让仿真时间很长,也会导致产生的仿真文件很大,所以我们可以通过直接修改参数的方式来缩短仿真的时间而看到相同的效果,且不会影响到RTL代码模块中的实际值,因为parameter定义的是局部参数,所以只在本模块中有效。
为了更好的区分,参数名我们习惯上都是大写。
rtl模块中的参数定义
模块名后定义参数
格式:
#(
parameter CNT_MAX = 25'd100,
parameter CNT_MAX_5 = CNT_MAX - 5
)
#+()
()内用parameter 参数名 = XX
()内的参数间用逗号分隔,最后一个参数后没有逗号
举例:
Verilog
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 参数名 = XX;
不同参数定义用分号结束语句
举例:
verilog
//=========================< Parameter >==============================
parameter CNT_MAX = 25'd100 ;
parameter CNT_MAX_5 = CNT_MAX - 5 ;
仿真模块中的参数修改
例化时修改
格式:
#(
.CNT_MAX (25'd24 ),
.CNT_MAX_5(25'd19)
)
#+()
()内用 .参数名(修改后的数值)
()内的参数间用逗号分隔,最后一个参数后没有逗号
举例:
Verilog
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
);
也可以去掉参数名,按顺序进行参数例化(但是不建议哦,不方便阅读):
verilog
#(
25'd24,
25'd19
)
defparam修改
格式:
defparam counter_inst.CNT_MAX = 25'd24 ;
defparam counter_inst.CNT_MAX_5 = 25'd19 ;
defparam 模块例化的参数名.模块中的参数 = 数值;
不同修改参数用分号结束语句
举例:
verilog
//=========================< 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修改 |
parameter定义参数 | 例化时修改 |
parameter定义参数 | defparam修改 |
-
如果rtl模块中既有模块名后定义参数 又有parameter定义参数 ,用defparam修改 会报错,用例化时修改 不报错。具体看建议与区别部分(4)
-
使用建议用模块名后定义参数 与例化时修改这一对应方案。
rtl中:
Verilog
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灯
);
仿真代码中:
Verilog
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部分:
verilog
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
仿真部分:
verilog
`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