上接 模块与端口
一、 概述
在进行模块调用时,有时需要修改模块中的参数,这个时候就需要进行参数化模块调用。
众所周知,参数都是有各自的作用域的。
-
`define
: 作用 -> 经常使用于定义常量能够跨模块、跨文件;
范围 -> 整个工程;
-
defparam
: 作用 -> 改写模块在端口声明时声明的参数,或模块实体中声明的参数;范围 - > 作用于例化模块;
-
parameter
: 作用 -> 经常使用于模块间参数传递;
范围 -> 本module内有效的定义;
-
localparam
: 作用-> 经常使用于状态机的参数定义;
范围 -> 本module内有效的定义,且不可用于参数传递;
二、 用法
当一个模块被另一个模块引用例化时,高层模块可以对低层模块的参数值进行改写。这样就允许在编译时将不同的参数传递给多个相同名字的模块,而不用单独为只有参数不同的多个模块再新建文件。参数覆盖有 2 种方式:1)使用关键字 defparam,2)带参数值模块例化。
-
使用关键字 defparam
defparam module_name.parameter1; module_name inst_name( port_map );
-
带参数值模块例化和模块例化基本一样,有两种调用方法:
module_name #( parameter1, //例化时,例化的参数顺序必须和模块顺序一致 parameter2 ) inst_name( port_map );
module_name #( .parameter_name(para_value),//必须指定当前例化的端口名称,顺序可以自由排序 .parameter_name(para_value) ) inst_name ( port map );
三、 两者区别
(1)所有参数都是模块在端口声明时声明的参数或参数都是模块实体中声明的参数,这两种模块参数改写的方式可混用。
(2) 利用 defparam 和带参数例化 都既可以改写模块在端口声明时声明的参数,也可以改写模块实体中声明的参数。但是 defparam 不能同时修改两种参数,也不能在有端口声明参数的情况下修改模块实体中生命的参数。
例如:
module ram
#( parameter AW = 2 ,
parameter DW = 3 )
(
input CLK ,
input [AW-1:0] A ,
input [DW-1:0] D ,
input EN ,
input WR , //1 for write and 0 for read
output reg [DW-1:0] Q );
parameter MASK = 3 ;
reg [DW-1:0] mem [0:(1<<AW)-1] ;
always @(posedge CLK) begin
if (EN && WR) begin
mem[A] <= D ;
end
else if (EN && !WR) begin
Q <= mem[A] ;
end
end
endmodule
此时再用 defparam 改写参数 MASK 值时,编译报 Error;
//都采用defparam时会报Error
defparam u_ram.AW = 4 ;
defparam u_ram.DW = 4 ;
defparam u_ram.MASK = 7 ;
ram u_ram (......);
//模块实体中parameter用defparam改写也会报Error
defparam u_ram.MASK = 7 ;
ram #(.AW(4), .DW(4)) u_ram (......);
(3)defparam 一般也不可综合。
(4)建议编写模块时,将需要修改的参数写入到模块端口声明之前的地方(用关键字井号 # 表示),例化时使用带参数值模块例化的方式。