跳转到主内容
思享编程网:思考分享,玩转编程世界!

Verilog基础:参数(parameter)的使用

相关阅读 Verilog基础https://blog.csdn.net/weixin_45791458/category_12263729.html?spm=1001.2014.3001.5482 参数(parameter)一般用于定义常数,常用于进行可配置的参数化设计中,本文将对参数的使用进行详细介绍。

首先来看看参数的BNF范式(语法),有关BNF范式相关内容,可以参考之前的文章。

图1 参数的定义 参数可分为两大类:局部参数和普通参数,分别由关键词 local_parameter 和 parameter 声明。

它们俩的区别在于,局部参数不允许使用defparam语句或在模块实例化时(在elaboration阶段)进行参数覆盖,普通参数在满足一定条件时允许参数覆盖。

需要注意的是参数代表常量,在运行时修改它们的值是非法的。

list_of_param_assignments是一个逗号分隔的赋值列表(这允许在一条语句中定义多个参数),其中赋值的右侧应该是常量表达式,只包含常数和之前已定义的参数。

localparam的声明位置 local_parameter可以在下面这些位置声明: 1、模块中

module example_module (

input wire clk, input wire rst, output wire [3:0] out );

localparam integer WIDTH = 4; // 在模块中声明localparam localparam [WIDTH-1:0] MAX_VALUE = 15;

reg [WIDTH-1:0] counter;

always @(posedge clk or posedge rst) begin if (rst) begin counter <= 0; end else if (counter < MAX_VALUE) begin counter <= counter + 1; end else begin counter <= 0; end end

assign out = counter;

endmodule 2、命名块中

module example_module (

input wire clk, input wire rst, output wire [3:0] out );

reg [3:0] counter;

always @(posedge clk or posedge rst) begin if (rst) begin counter <= 0; end else begin // 命名块 begin: COUNTER_LOGIC localparam integer MAX_COUNT = 10; // 在命名块中声明localparam

if (counter < MAX_COUNT) begin counter <= counter + 1; end else begin counter <= 0; end end end end

assign out = counter;

endmodule

3、任务中

module example_module;

reg [3:0] value;

task example_task; localparam integer MAX_VALUE = 10; // 在任务内部声明localparam

input reg [3:0] in_value; output reg [3:0] out_value; begin if (in_value < MAX_VALUE) begin out_value = in_value + 1; end else begin out_value = 0; end end endtask

initial begin value = 5; example_task(value, value); end

endmodule 4、函数中

module example_module;

reg [3:0] input_value; reg [3:0] output_value;

function [3:0] example_function; localparam integer MAX_VALUE = 8; // 在函数内部声明localparam

input [3:0] in_value; begin if (in_value < MAX_VALUE) begin example_function = in_value + 1; end else begin example_function = 0; end end endfunction

initial begin input_value = 5; output_value = example_function(input_value); $display("Output Value: %d", output_value); end

endmodule

5、在生成块中

module example_module (

output reg [7:0] out );

generate if (1) begin: GEN_BLOCK_LOW localparam integer WIDTH = 8; // 在生成块中声明localparam always @(*) begin out = WIDTH; end end else begin: GEN_BLOCK_HIGH localparam integer WIDTH = 16; // 在生成块中声明另一个localparam always @(*) begin out = WIDTH; end end endgenerate

endmodule parameter 的声明位置 parameter可以在下面这些位置声明: 1、模块参数列表中

module example_module #(

parameter integer WIDTH = 8, // 在模块参数声明列表中声明parameter parameter integer DEPTH = 16 )( input wire [WIDTH-1:0] data_in, output reg [WIDTH-1:0] data_out );

reg [WIDTH-1:0] memory [0:DEPTH-1];

always @(*) begin data_out = memory[data_in % DEPTH]; end

endmodule 2、模块中

module example_module (

input wire [3:0] select, output reg [7:0] out );

parameter integer WIDTH = 8; // 在模块内部声明parameter parameter integer OFFSET = 5;

always @(*) begin out = (select * WIDTH) + OFFSET; end

endmodule

3、命名块中

module example_module (

input wire [3:0] select, output reg [7:0] out );

always @(*) begin // 命名块 begin : MY_BLOCK parameter integer MULTIPLIER = 4; // 在命名块中声明 parameter parameter integer OFFSET = 2;

out = (select * MULTIPLIER) + OFFSET; end end

endmodule

4、任务中

module example_module;

reg [3:0] value;

task example_task; parameter integer MAX_VALUE = 10; // 在任务内部声明parameter input reg [3:0] current_value; output reg [3:0] next_value; begin if (current_value < MAX_VALUE) begin next_value = current_value + 1; end else begin next_value = 0; end end endtask

initial begin value = 5; example_task(value, value); $display("Value after increment: %d", value); end

endmodule

5、函数中

module example_module;

reg [3:0] input_value; reg [3:0] output_value;

function [3:0] example_function; input [3:0] in_value; parameter integer MAX_VALUE = 8; // 在函数内部声明的parameter begin if (in_value < MAX_VALUE) begin example_function = in_value + 1; end else begin example_function = 0; end end endfunction

initial begin input_value = 5; output_value = example_function(input_value); $display("Output Value: %d", output_value); end

endmodule 符号、位宽和类型 参数声明时可以指定可选的有符号、位宽和类型,但如果指定了符号和位宽,则不能指定类型,也就是说有以下搭配: 不指定有符号、位宽和类型:参数为无符号的,参数的位宽由所有参数覆盖完成后,最后赋给参数的结果相同。

指定有符号,不指定位宽和类型:参数为有符号的,参数的位宽由所有参数覆盖完成后,最后赋给参数的结果相同。

指定位宽,不指定有符号和类型:参数为无符号的,参数的位宽由指定位宽决定。

指定有符号和位宽,不指定类型:参数为有符号的,参数的位宽由指定位宽决定。

指定类型,不指定有符号和位宽:参数是否有符号和位宽取决于具体的类型(例如对于time类型是无符号的且位宽至少64位,而对于integer类型,是有符号的且位宽至少32位)。

参数的覆盖 模块参数列表和模块中定义的参数在满足一定条件时,可以进行参数覆盖(本文只涉及在模块实例化时的参数覆盖)。

模块参数列表中定义的参数可以像端口连接类似,使用位置参数覆盖或命名端口覆盖,如例1所示。

// 例1

module top_module; reg input_data; wire output_data;

// 位置端口覆盖PARAM1和PARAM3,保留PARAM2的默认值 my_module #(12, 16, 64) instance1 ( .data_in(input_data), .data_out(output_data) );

// 命名端口覆盖PARAM1和PARAM3,保留PARAM2的默认值 my_module #( .PARAM1(12), // 覆盖PARAM1为12 .PARAM3(64) // 覆盖PARAM3为64 ) instance2 ( .data_in(input_data), .data_out(output_data) );

endmodule

module my_module #( parameter PARAM1 = 8, parameter PARAM2 = 16, parameter PARAM3 = 32 )( input data_in, output reg data_out );

initial $display("%d, %d, %d",PARAM1, PARAM2, PARAM3); endmodule 模块中定义的参数, 在模块列表中没有定义参数时 ,可以使用位置参数覆盖或命名端口覆盖,在进行位置参数覆盖时顺序与参数定义的顺序相同。

需要注意的是,在进行位置参数覆盖时,如果想不覆盖某个参数,则需要将该参数的值重新写一遍,而不像位置端口连接,如果想表示某个端口没连接,直接留空即可,如例2所示。

// 例2

module top_module; reg input_data; wire output_data;

// 位置端口覆盖PARAM1和PARAM3,保留PARAM2的默认值 my_module #(12, 16, 64) ) instance1 ( .data_in(input_data), .data_out(output_data) );

// 命名端口覆盖PARAM1和PARAM3,保留PARAM2的默认值 my_module #( .PARAM1(12), // 覆盖PARAM1为12 .PARAM3(64) // 覆盖PARAM3为64 ) instance1 ( .data_in(input_data), .data_out(output_data) );

endmodule

module my_module ( // 此处不能定义参数,否则模块中定义的参数无法覆盖 input data_in, output reg data_out );

parameter PARAM1 = 8; parameter PARAM2 = 16; parameter PARAM3 = 32; initial $display("%d, %d, %d",PARAM1, PARAM2, PARAM3); endmodule 参数覆盖的过程,就和普通的赋值一样,右侧表达式中操作数的位宽可能会受到左侧参数位宽(如有)的影响,而右侧表达式的符号不受左侧参数的符号影响,详情见以下两文。

Verilog基础:表达式位宽的确定(位宽拓展)-CSDN博客文章浏览阅读1.1w次,点赞137次,收藏181次。

我们可以首先找到被加入上下文环境的操作数,a和b作为+操作符的操作数,是上下文决定的,(a+b)作为整体位与移位操作符的左边也是上下文决定的,(a+b)>>1作为整体是=操作符的右操作数,也是上下文决定的,因此answer(因为=),a,b(因为三层上下文嵌套)都被加入上下文环境中,这三个变量的位宽都是一样的,所以他们三个在运算前不会有拓展。

因此首先执行a+b,根据规则,结果为16位,进位被丢失,然后再右移一位,最高位补0,最后赋值给同为16位的answer。

很多时候方法很简单。

改成a+b+17'b0;_verilog动态位宽https://chenzhang.blog.csdn.net/article/details/128772558?spm=1001.2014.3001.5502 Verilog基础:表达式符号的确定-CSDN博客文章浏览阅读846次,点赞15次,收藏39次。

文章介绍了Verilog中处理表达式符号的重要性和规则,包括$signed和$unsigned函数的作用。

强调了位选、域选、拼接操作的结果通常为无符号数,以及在加法操作中,如果上下文操作数包含无符号数,则结果也会是无符号的,可能导致预期外的结果。

解决这个问题的方法是确保所有操作数的符号一致。

https://blog.csdn.net/weixin_45791458/article/details/128840843?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522677A413D-10AF-4A54-82E7-5B5203BB4177%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=677A413D-10AF-4A54-82E7-5B5203BB4177&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_ecpm_v1~rank_v31_ecpm-5-128840843-null-null.nonecase&utm_term=%E8%A1%A8%E8%BE%BE%E5%BC%8F&spm=1018.2226.3001.4450

相关文章