首页 > 解决方案 > 基于接口参数化模块(SystemVerilog)

问题描述

我在 SystemVerilog 中有一个高度分层的设计(使用 Xilinx Vivado 合成)。我使用参数化的接口和模块。接口内的某些数据类型是使用(接口内部)函数根据它们的参数计算的。我希望能够在使用这些接口的模块中访问这些类型的信息(特别是位宽)。似乎我可以从模块内的接口实例化类型,但不能将位宽用作常量

也就是说,鉴于以下情况:

interface iface #(PARAM=1);
    const int i = PARAM; //Gives a warning about simultaneous procedural and continuous assignment
    typedef logic [PARAM-1:0] t;
    t s;
endinterface

module test(iface i);
    i.t s; //Works
    const int size1 = $bits(i.s); //Works
    const int size2 = $bits(s); //Works
    localparam int p = $bits(i.s); //Fails: Heirarchial name access not allowed

    wire [size1-1:0] s1; //Fails: "size1" is not constant
    wire [size2-1:0] s2; //Fails: "size2" is not constant
    wire [i.i-1:0] s3; //Fails: "i" is not constant
    wire [p-1:0] s3; //Would have worked, is "p" was defined

    localparam int p2 = i.i; //Fails: "i" is not constant
    localparam int p3 = i.PARAM; //Fails: Heirarchial name access not allowed
    //Any of the above two lines would solve all my problems
endmodule

我尝试了几种解决方案,包括使用包。但在那种情况下,似乎没有办法从顶级参数初始化包参数。

我阅读了有关接口和包的 SystemVerilog LRM,但在那里找不到任何解决方案。

任何解决方案(除了在接口之外计算派生参数并将它们传递到层次结构中)或正确方向的指针都将受到高度赞赏。

标签: verilogsystem-veriloghdl

解决方案


System Verilog 中有一个令人困惑的部分。const int和其他不是verilog意义上的常数。它们只是 const 变量。const 关键字只是与运行时系统的合同,不会在运行时修改它们。

“实”常数是parameters 和localparams。这些是编译时间(精化时间)常量。只有它们可以用于宽度声明。因此,您的案例中会出现一堆问题。

第二点是只有变量和函数的实例才能被跨模块引用访问。不是这样的typedef东西,所以你不能以这种方式引用它。您可能还应该能够访问参数并在模块内定义您的 typdef:

module test(iface i);
 typedef logic [i.PARAM - 1: 0] t;
 t s;

以上只有一个问题:它不适用于所有编译器。它适用于 vcs,但不适用于 nc。

如果你想通用,我建议你将模块和接口参数化为相同的值。

module test#(PARAM = 1) (iface i);
  typedef logic [PARAM - 1: 0] t;
  t s;

  const int size1 = $bits(i.s); //Works
  const int size2 = $bits(s); //Works
  localparam int p = $bits(i.s); //Fails: Heirarchial name access not allowed

  wire [p-1:0] s4; //Would have worked, is "p" was defined

  localparam int p3 = PARAM; 
endmodule

module top;
  localparam P8 = 8; // could be from a package
  iface #(.PARAM(P8)) i8();
  test #(.PARAM(P8)) test(i8);
endmodule 

现在,这始终是一个节奏问题localparam int p = $bits(i.s);它适用于 synopsys。所以,只是不要使用它。你仍然可以说local int p = PARAM;


推荐阅读