📜  Verilog参数

📅  最后修改于: 2021-01-11 14:52:34             🧑  作者: Mango

Verilog参数

在Verilog中,参数是常量,并且不属于任何其他数据类型,例如寄存器或网络数据类型。

常数表达式是指常数或先前定义的参数。我们无法在运行时修改参数值,但是可以使用defparam语句修改参数值。

defparam语句只能在编译时修改参数。可以使用带有模块实例化的#delay规范来修改参数值。

在Verilog中,有两种方法可以在模块实例化时覆盖模块参数值。

  • 通过使用defparam关键字。
  • 和模块实例参数值分配。

在defparam关键字之后,将层次结构路径指定给参数和参数的新值。这个新值应该是一个常量表达式。如果右侧表达式引用了任何参数,则应在调用defparam的模块内声明它。

模块实例参数值的分配方法似乎是将延迟分配给门实例。当实例化模块中的参数出现在模块中时,此方法将覆盖它们。使用这种格式,不能跳过参数。

常量表达式可以包含先前声明的参数。当检测到先前声明的参数发生更改时,所有依赖于该值的参数都会自动更新。

考虑一下,可以对4位加法器进行参数化以接受位数的值,并且可以在模块实例化期间传递新的参数值。因此,一个N位加法器将转换为4位,8位或16位加法器。他们就像参数是一个函数调用时传递的函数。

parameter MSB = 7;                  // MSB is a parameter with the constant value 7 
parameter REAL = 4.5;               // REAL holds the real number 
parameter FIFO_DEPTH = 256,
          MAX_WIDTH = 32;           // Declares two parameters
parameter [7:0] f_const = 2'b3;     // 2 bit value is converted into 8 bits; 8'b3 

有两种类型的参数,模块指定,并且都接受范围说明。但是,它们的大小与要存储的值一样宽,因此不需要范围指定。

模块参数

它可用于覆盖模块内的参数定义,并使模块在编译时具有一组不同的参数。可以使用defparam语句修改参数。通常在参数名称中使用大写字母以立即注意到它们。

下面的模块使用参数来指定设计中的总线宽度,数据宽度和FIFO的深度,并且在实例化模块或使用defparam语句时,可以使用新值覆盖这些模块。

module design_ip  ( addr, wdata, write, sel, rdata);
     parameter  BUS_WIDTH    = 32,
                DATA_WIDTH   = 64,
                FIFO_DEPTH   = 512;
     input addr;
     input wdata;
     input write;
     input sel;
     output rdata;
     wire [BUS_WIDTH-1:0] addr;
     wire [DATA_WIDTH-1:0] wdata;
     reg  [DATA_WIDTH-1:0] rdata;
     reg [7:0] fifo [FIFO_DEPTH];
endmodule

在新的ANSI风格的Verilog端口声明中,我们可以声明以下参数:

module design_ip
    #(parameter BUS_WIDTH=32,
        parameter DATA_WIDTH=64) 
           (input [BUS_WIDTH-1:0] addr,
// other port declarations
   );

覆盖参数

在模块实例化期间,可以使用新值覆盖参数。第一部分是名为d0的名为design_ip的模块,其中新参数在#()中传递。

第二部分是使用称为defparam的Verilog构造来设置新的参数值。第一种方法通常用于在RTL设计中传递新参数。第二种方法在测试平台仿真中用于快速更新设计参数,而无需重新实例化模块。

module tb;
      // Module instantiation override
     design_ip  #(BUS_WIDTH = 64, DATA_WIDTH = 128) d0 ( [port list]);
    // Use of defparam to override
    defparam d0.FIFO_DEPTH = 128;
endmodule

模块计数器具有两个参数NDOWN ,它们声明为默认值2和0。

N控制输出中的位数,有效控制计数器的宽度。默认情况下,它是一个2位计数器。

参数DOWN控制计数器是递增还是递减。由于参数设置为0,因此计数器将减少。

2位向上计数器

module counter
  # ( parameter N = 2, parameter DOWN = 0)

  (input clk, input rstn, input en, output reg [N-1:0] out);

  always @ (posedge clk) begin
    if (!rstn) begin
      out <= 0;
    end else begin
      if (en)
        if (DOWN)
          out <= out - 1;
        else
              out <= out + 1;
      else
         out <= out;
    end
  end
endmodule

模块计数器使用N实例化为2,即使它不是必需的,因为默认值为2。

在模块实例化期间不传递DOWN。并且它采用默认值0,使其递增计数。

module design_top (input clk, input rstn, input en, output [1:0] out);
    counter #(.N(2)) u0 (.clk(clk), .rstn(rstn), .en(en));
endmodule

默认参数用于实现计数器,其中N等于2,使其成为2位计数器,而DOWN等于0,使其成为递增计数器。计数器的输出在顶层未连接。

4位递减计数器

在这种情况下,模块计数器以N实例化为4,使其成为4位计数器。在模块实例化期间,将DOWN的值传递为1,因此实现了递减计数器。

module design_top (input clk, input rstn, input en, output [3:0] out);
    counter #(.N(4), .DOWN(1)) 
               u1 (.clk(clk), .rstn(rstn), .en(en));
endmodule

指定参数

这些参数用于提供时间和延迟值,并使用specparam关键字声明。允许在指定的块和主模块体内使用。

// Use of specify block
Specify
    specparam  t_rise = 200, t_fall = 150;
    specparam  clk_to_q = 70, d_to_q = 100;
endspecify
// Within main module
module  my_block ( );
     specparam  dhold = 2.0;
     specparam  ddly  = 1.5;
     parameter  WIDTH = 32;
endmodule

指定参数和模块参数之间的区别

Specify parameter Module parameter
Specify the specparam keyword declares parameter. The module parameter is declared by parameter.
It can be declared inside a specific block or within the main module. It can only be declared within the main module.
This parameter may be assigned specparams and parameters. This may not be assigned specparams.
SDF can be used to override values. Instance declaration parameter values or defparam can be used to override.

笔记

以下是有关Verilog参数的一些重要说明,例如:

  • 如果使用defparam语句,则必须指定参数的分层路径。
  • 我们不能跳过模块实例参数值分配中的参数。如果需要执行此操作,请将初始值用于未覆盖的参数。
  • 当一个参数依赖于另一个参数时,如果我们更改第一个参数,则第二个参数将自动更新。