在Verilog中,parameter
和 localparam
都用于定义常量,但是它们之间有一些重要的区
-
作用范围:
-
parameter:可以在模块外部被修改或重定义。它可以被作为模块的参数传递给其他模块,因此具有较广泛的作用范围,适用于设计中需要在多个地方使用的常量。
-
localparam:只能在定义它的模块内使用,不能被外部修改。
localparam
常用于定义模块内部的常量,这些常量不希望被外部更改。
-
-
可修改性:
-
parameter:是可以在实例化模块时修改的常量。换句话说,当模块被实例化时,可以通过提供不同的参数值来改变其行为。
-
localparam:不能在模块实例化时被修改,它的值只能在模块内部定义,并且始终保持固定。
-
-
默认值:
-
parameter:在模块定义时可以为其指定默认值,但该值可以在模块实例化时被修改。
-
localparam:它的值只能在模块定义时设置,无法在模块实例化时修改。
-
-
典型使用场景:
-
parameter:用于那些可能会根据不同模块实例化的需求而变化的常量,例如控制信号宽度、数据位数等。
-
localparam:用于模块内部需要使用的常量,这些常量不需要暴露给模块的外部使用。比如在实现复杂功能时,常用来定义一些中间计算值。
-
语法示例:
module example (input wire clk,input wire rst
);// parameter可以在实例化时修改parameter WIDTH = 8;// localparam不可以在外部修改localparam DELAY = 5;reg [WIDTH-1:0] data;reg [DELAY-1:0] delay_reg;always @(posedge clk or posedge rst) beginif (rst) begindata <= 0;delay_reg <= 0;end else begindata <= data + 1;delay_reg <= delay_reg + 1;endend
endmodule
在上面的例子中,WIDTH
是一个 parameter
,可以在实例化模块时被修改,而 DELAY
是一个 localparam
,它只能在模块内部使用,无法在实例化时被改变。
例化时修改parameter的值
在Verilog中,如果你想在实例化时修改 parameter
的值,你可以在实例化模块时指定一个新的值。localparam
是不能在实例化时修改的,所以只能修改 parameter
。
module adder #(parameter WIDTH = 8) (input wire [WIDTH-1:0] a, // 输入信号a,位宽由WIDTH决定input wire [WIDTH-1:0] b, // 输入信号b,位宽由WIDTH决定output wire [WIDTH-1:0] sum // 输出结果,位宽由WIDTH决定
);assign sum = a + b; // 进行加法操作
endmodule
例化后
module top;reg [15:0] a, b; // 定义两个16位输入信号wire [15:0] sum; // 定义16位输出信号// 实例化adder模块,修改WIDTH为16adder #(16) u_adder (.a(a),.b(b),.sum(sum));initial begin// 给输入信号赋值a = 16'hAAAA;b = 16'h5555;// 输出结果#10; // 延时,模拟一段时间后输出$display("a = %h, b = %h, sum = %h", a, b, sum);end
endmodule
在上面的代码中:
我们实例化了 adder
模块,并在实例化时通过 #(16)
修改了 WIDTH
为 16。这意味着 a
、b
和 sum
信号的位宽都会是 16 位,而不是默认的 8 位。在 initial
块中,给 a
和 b
信号赋值,进行加法操作,最后输出结果。
修改多个parameter
底层代码:
module multiplier_adder #(parameter WIDTH_A = 8, // 输入A的位宽parameter WIDTH_B = 8, // 输入B的位宽parameter OP_MODE = 0 // 操作模式:0 表示加法,1 表示乘法) (input wire [WIDTH_A-1:0] a, input wire [WIDTH_B-1:0] b, output wire [WIDTH_A-1:0] sum, // 输出加法结果output wire [WIDTH_A-1:0] product // 输出乘法结果
);// 加法操作assign sum = a + b;// 乘法操作assign product = (OP_MODE == 1) ? (a * b) : 0; // 只有在OP_MODE为1时进行乘法计算endmodule
实例化模块并修改多个 parameter
的值
接下来,我们将修改 WIDTH_A
、WIDTH_B
和 OP_MODE
的值来定制模块的行为(按顺序的方式进行修改)。
module top;reg [15:0] a, b; wire [15:0] sum, product; // 实例化multiplier_adder模块,修改WIDTH_A为16,WIDTH_B为8,OP_MODE为1(乘法模式)multiplier_adder #(16, 8, 1) u_multiplier_adder (.a(a),.b(b),.sum(sum),.product(product));initial begina = 16'hAAAA; // a的值为16位的十六进制数b = 8'h55; // b的值为8位的十六进制数#10;$display("a = %h, b = %h, sum = %h, product = %h", a, b, sum, product);end
endmodule
命名参数实例化
module top;reg [15:0] a, b; // 定义16位输入信号wire [15:0] sum, product;multiplier_adder #(.WIDTH_A(16), // 指定WIDTH_A为16.OP_MODE(1), // 指定OP_MODE为1(乘法).WIDTH_B(8) // 指定WIDTH_B为8) u_multiplier_adder (.a(a),.b(b),.sum(sum),.product(product));initial begina = 16'hAAAA;b = 8'h55;#10;$display("a = %h, b = %h, sum = %h, product = %h", a, b, sum, product);end
endmodule
总结:
顺序修改:通常情况下,parameter
的值是按顺序修改的,传递的顺序必须和模块定义中的 parameter
顺序一致。
命名参数:为了不按照顺序修改参数,可以使用命名参数(parameter_name(value)
)的方式指定每个 parameter
的值,这样可以确保修改的准确性,并且使代码更具可读性。