• Verilog基础语法——parameter、localparam与`define


    Verilog基础语法——parameter、localparam与`define

    写在前面

      在使用Verilog编写RTL代码时,如果需要定义一个常量,可以使用`define、parameter和localparam三种进行定义与赋值。

    一、localparam

      localparam是一种局部常量,只在声明该常量的模块中有效,不可用于模块与模块之间的参数传递。一般在定义仅用于模块内部的参数时使用localparam,比如状态机状态的定义声明。例如:

    // FSM Sate
    localparam IDLE         = 4'b0001;
    localparam INPUT        = 4'b0010;
    localparam DECODE       = 4'b0100;
    localparam COMPLETE     = 4'b1000;
    
    // FSM
    always @(posedge clk or negedge rst_n) begin
        if(!rst_n) begin
            curr_state <= IDLE;
            //...
        end
        else begin
            case(curr_state) 
                IDLE:
                begin
                	if(start)
                        curr_state <= INPUT;
                    else
                    	curr_state <= IDLE;
                    //...             
                end
    
                INPUT   :
                begin
                    curr_state <= DECODE;
                    //...
                end
    
                DECODE      :        
                begin
                	curr_state <= COMPLETE;
                    //... 
                end
    
                ALL_COMPLETE:
                begin
                	curr_state <= IDLE;
                end
    
                default :;
            endcase
        end
    end
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    二、parameter

      parameter与localparam相同的是,其作用范围仅仅是声明该参数的模块内部,而不同的是,parameter可以用于模块之间的参数传递,一般用于参数化设计。参数化设计是指对于所设计的功能子模块,通过修改其内部参数值即可使得该模块适用于其他场景。
      这里,parameter可以分为在模块头部中声明与在模块内部定义声明,两种定义方式需要不同的方式来进行参数传递。

    (1)在模块头部中定义
      在模块头部中定义参数是一种常用的做法,其格式如下:

    module counter
    #(
        parameter CNT_NUM    = 8'd128 ,
        parameter DIN_WIDTH  = 4'd8   ,
        parameter DOUT_WIDTH = 5'd16   
    )
    (
        input    wire    [DIN_WIDTH-1:0]    din , 
        output   wire    [DOUT_WIDTH-1:0]   dout
    );
        // 模块内部代码
        // ...
    
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

      而在模块例化时,需要与例化模块输入输出端口一样,给参数接入不同的数值即可,其格式如下:

    module top
    (
        // 输出输入声明
        // ...
    );
    
        localparam CNT_NUM = 8'd100;
        localparam DIN_WIDTH  = 4'd6;
        localparam DOUT_WIDTH = 5'd12;   
    
        wire    [DIN_WIDTH-1:0]    counter_din ; 
        wire    [DOUT_WIDTH-1:0]   counter_dout;
    
    
        // 模块例化
        counter 
        #(
            .CNT_NUM   (CNT_NUM   ), // 参数传递
            .DIN_WIDTH (DIN_WIDTH ), // 参数传递
            .DOUT_WIDTH(DOUT_WIDTH)  // 参数传递
        )
        counter_inst
        (
            .din (counter_din ), 
            .dout(counter_dout)
        )
        // ...
    
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    (2)在模块内部定义
      在模块内部定义的paramter其格式如下:

    module counter
    (
        input    wire    [15:0]   din , 
        output   wire    [7:0]    dout
    );
    
        parameter CNT_NUM    = 8'd128 ;
        parameter DIN_WIDTH  = 4'd8   ;
        parameter DOUT_WIDTH = 5'd16  ;
    
        // 模块内部代码
        // ...
    
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

      在上层模块的例化中可以通过defparam进行修改所例化模块中定义参数的值,其格式如下:

    module top
    (
        // 输出输入声明
        // ...
    ) ;
    
        wire    [15:0]    counter_din ; 
        wire    [7:0]     counter_dout;
    
        // 模块例化
        counter counter_inst
        (
            .din (counter_din ), 
            .dout(counter_dout)
        );
    	
    	// 格式:
    	// defparam 模块例化名称 参数名称 = 重新设定的参数值
    	// 如果是多层嵌套子模块,在模块3中例化模块2,在模块2中例化模块1,则格式为:
    	// defparam 模块3例化名称 模块2例化名称 模块1例化名称 参数名称 = 重新设定的参数值
        defparam counter_inst CNT_NUM = 8'd100;
        defparam counter_inst DIN_WIDTH  = 4'd6;
        defparam counter_inst DOUT_WIDTH = 5'd12; 
    
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

      这种方式的缺点在于:该方式声明的parameter无法用于模块输入输出信号位宽的控制,因为参数定义声明在模块的内部。

    三、`define

      通过`define定义的参数作用范围是整个设计工程文件,遇到`undef则失效,其格式如下:

    `define CNT_NUM 8'd128
    module counter
    (
        // 输出输入声明
        // ...
    )
    
        // 模块内部代码
        // ...
    
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

      也可以将所以`define定义声明的参数放在一个单独文件中,并在每个模块中使用`include包含声明文件,以作用于整个工程项目。其格式如下:

    // para_def.vh
    // 独立参数声明文件
    `define CNT_NUM 8'd128
    `define DIN_WIDTH  4'd6;
    `define DOUT_WIDTH 5'd12; 
    
    • 1
    • 2
    • 3
    • 4
    • 5

      然后再每个模块的前面使用`include包含该参数声明文件即可使用,格式如下:

    // `include "路径/参数声明文件名"
    `include "F/xxx/RTL/para_def.vh"
    module counter
    (
        // 输出输入声明
        // ...
    )
     
        // 模块内部代码
        // ...
    	
    	// 使用格式:`参数名
    	always @(posedge clk) begin
    		if(cnt == `CNT_NUM)
    			
    		else
    		
    	end
    
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    写在最后

      在本文中,我们学习了Verilog基础语法中三种不同的参数定义方式——localparam、parameter与`define,其中,`define定义的参数作用范围最广,且支持用于模块之间的参数传递;localparam作用范围仅为模块内部,且不支持参数传递;而parameter是两者的折中,作用范围为模块内部,但是支持参数传递。在实际代码编写过程中,应选择合适的方式对不同参数进行声明,使用时可以参考下表。

    关键字适用场景
    localparam仅用于模块内部的参数,且在不同场景下无需进行修改
    parameter仅用于模块内部的参数,但是在不同场景下需要进行修改
    `define整个工程文件中都会用到的参数

      本文到此结束,欢迎评论区交流探讨。

    在这里插入图片描述

  • 相关阅读:
    Mysql索引
    用golang开发系统软件的总结
    演练 成员内部类
    卷积神经网络的常用改进
    欧拉路径与欧拉回路
    XTTS系列之五:警惕大文件表空间
    hi mate, lets recall the bloody “JOIN“
    AWS清除CloudFront缓存
    Android studio在Ubuntu桌面上 创建桌面图标,以及导航栏图标
    Kafka 消息中间件
  • 原文地址:https://blog.csdn.net/qq_42224089/article/details/133690339