当前位置: 首页 > article >正文

Verilog:参数(parameter)的使用

相关阅读

Verilog基础icon-default.png?t=O83Ahttps://blog.csdn.net/weixin_45791458/category_12263729.html?spm=1001.2014.3001.5482


        参数(parameter)一般用于定义常数,常用于进行可配置的参数化设计中,本文将对参数的使用进行详细介绍。

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

图1 参数的定义

        参数可分为两大类:局部参数和普通参数,分别由关键词local_parameterparameter声明。它们俩的区别在于,局部参数不允许使用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, ,64)
    ) instance1 (
        .data_in(input_data[11:0]), 
        .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 #(
    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.5502Verilog基础:表达式符号的确定-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


http://www.kler.cn/news/367739.html

相关文章:

  • Python浪漫之画星星
  • [Python学习日记-57] 常用模块的练习(答案更新中)
  • Fast Simulation of Mass-Spring Systems in Rust 论文阅读
  • 【自然语言处理】BERT模型
  • 传输层TCP
  • 【AI换装整合及教程】CatVTON:时尚与科技的完美融合
  • 嵌入式——STM32外设应用
  • 抖音列表页采集-爬虫部分(2)
  • B/S架构的诊所药店云his管理系统源码,云门诊管理系统,自主知识产权,支持二次开发
  • iOS Swift逆向——deMangle过程中的偏移计算
  • 算法|牛客网华为机试10-20C++
  • 学点高数-数学上的集合①-集合的基本概念
  • 学成在线实战
  • 机器学习 - 树结构1 - 随机森林
  • Spring Cloud --- Sentinel 规则持久化
  • YOLO11改进 | 卷积模块 | 卷积模块替换为选择性内核SKConv【附完整代码一键运行】
  • 设计模式概览
  • 手机拍证件照,换正装有领衣服及底色的方法
  • jenkins配置邮件通知
  • Flutter控制台提示setState() or markNeedsBuild() called during build错误
  • Linux中DNS搭建
  • GenAI 生态系统现状:不止大语言模型和向量数据库
  • Day 8 UE5c++
  • React实现购物车功能
  • 川渝地区软件工程考研择校分析
  • Pulsar mq 设置延迟消息模式 pulsar mq 发送延迟消息 pulsar如何发送消费延时消息