欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Verilog中Parameter用法-常量定义与参数传递(例化传递、defparam传递)

程序员文章站 2024-02-22 21:26:04
...

    Verilog中用parameter来定义常量,即用parameter来定义一个标识符来代表一个常量,称为符号常量,即标识符形式的常量,采用标识符代表一个常量可以提高程序的可读性和可维护性。另一个很有用的用途就是可以利用defparam或者在模块实例化的时候进行参数传递(即重写)

一、parameter声明常量


    parameter定义常量,可以定义在模块内部或外部;常用于定义位宽或时间延迟(易变),此处以加一个常数的电路进行示例,如下:

定义方式为: parameter 标识符 = (位宽)常数;// 位宽默认为32位,如果指定位宽则以指定值为准

parameter在模块内部定义常量:


module param_idef(
    input clk,
    input [2:0]din,
    output reg [3:0]sum
    );

parameter ADD = 2'd1;
aaa@qq.com(posedge clk)
begin
    sum <= din+ADD;
end
endmodule

parameter在模块外部定义常量:


module param_odef
#(parameter ADD2 = 2'd1)
(
    input clk,
    input [2:0]din,
    output reg [3:0]sum
    );

aaa@qq.com(posedge clk)
begin
    sum <= din+ADD2;
end
endmodule

 测试文件如下:

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: CLL
// 
// Create Date: 2020/02/22 12:22:02
// Design Name: 
// Module Name: param_tsb
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module param_tsb(

    );
//
reg clk;
reg [2:0]din;
wire [3:0]sum1,sum2;
//
initial
begin
    clk = 1'b1;
    forever #10 clk = ~clk;
end
//
initial
begin
    din = 3'd3;
    #80 din = 3'd1;
    #40 din = 3'd0;
end

param_idef inst1(
    .clk(clk),
    .din(din),
    .sum(sum1)
);
param_odef inst2(
    .clk(clk),
    .din(din),
    .sum(sum2)
);
endmodule

输出为:

Verilog中Parameter用法-常量定义与参数传递(例化传递、defparam传递)

简单验证了两种定义方式的正确性;

二、parameter用于提高程序的可读性和可维护性

可维护性:

与软件编程类似,通过改变parameter定义的常量值,实现代码所有用到这一标识符部分的值,便于修改与维护;

可读性:

标识符按照常量实际意义取名,增强可读性;

三、参数传递(重写)

子模块利用parameter定义常量,被顶层调用时默认为子模块中参数

模块调用修改参数:

参数改变时,可在顶层模块调用子模块时进行参数修改;如:
    module Top(...);//这是一个顶层模块
        Decode #(4,0) U_D1(); //使得Width = 4, Polarity = 0;
        Decode #(5) U_D2(); //使得 Width = 5,Polarity 不变,即为1;
    endmodule

    module Decode(A,F);    //这是一个子模块
        parameter Width = 1, Polarity = 1;
        ......
    endmodule

利用defparam修改参数:

参数改变时,也可在利用defparam进行参数修改;如:
    module Top(...);//这是一个顶层模块

        defparam    U_D1.Width = 4;
        defparam    U_D1.Polarity = 0;
//使得U_D1的Width = 4, Polarity = 0;

        defparam    U_D2.Width = 5;//使得U_D2的Width = 5,Polarity 不变,即为1;
        Decode U_D1();
        Decode U_D2();
    endmodule


    module Decode(A,F);    //这是一个子模块
        parameter Width = 1, Polarity = 1;
        ......
    endmodule

四、仿真验证:

设计一个位宽可变半加器,默认位宽为4bit,并且位宽可调;

半加器设计如下:

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: CLL
// 
// Create Date: 2020/02/22 14:05:33
// Design Name: 
// Module Name: counter
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module counter
#(parameter W = 3)
(
    input [W:0]din1,
    input [W:0]din2,
    output [W:0]sum,
    output cout
    );
assign {cout,sum} = din1+din2;
endmodule

修改参数仿真如下:

例化1为默认参数,位宽应为4;

例化2实例化时传递参数,传递位宽为6;(注意参数传递位置,在模块名称counter之后,实例名称istN之前)

例化3利用defparam传递参数,传递位宽为6;(注意参数赋值与例化时端口赋值一样,可以位置赋值,也可以按照名称赋值;仿真采用名称赋值;也可部分参数赋值,未赋值参数保持默认)

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: CLL
// 
// Create Date: 2020/02/22 14:10:50
// Design Name: 
// Module Name: count_inst
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module count_inst(
    input [3:0]din1,
    input [3:0]din1_2,
    input [5:0]din2,
    input [5:0]din2_2,
    input [5:0]din3,
    input [5:0]din3_2,
    output [3:0]sum1,
    output cout1,
    output [5:0]sum2,
    output cout2,
    output [5:0]sum3,
    output cout3
    );
// adder1 4bit,默认
    counter inst1(
        .din1(din1),
        .din2(din1_2),
        .sum(sum1),
        .cout(cout1)
    );
// adder2 6bit,例化传递
    counter  #(.W(5)) inst2(
        .din1(din2),
        .din2(din2_2),
        .sum(sum2),
        .cout(cout2)
    );
// adder3 6bit,defparam传递
defparam inst3.W = 5;
    counter inst3(
        .din1(din3),
        .din2(din3_2),
        .sum(sum3),
        .cout(cout3)
    );

endmodule

对应RTL电路如下:

Verilog中Parameter用法-常量定义与参数传递(例化传递、defparam传递)

通过例化结果的位宽,证明验证通过;

五、参考文献:

Verilog 参数Parameter篇

Verilog中的parameter

Verilog基础知识0(`define、parameter、localparam三者的区别及举例)

【Verilog HDL】参数(Parameter)的作用案例