基于接口参数化模块(SystemVerilog)

问题描述 投票:1回答:2

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

也就是说,给出以下内容:

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,但在其中找不到任何解决方案。

高度赞赏任何解决方案(不计算接口外部的派生参数并将其向下传递到层次结构中)或指向正确方向的指针。

verilog system-verilog hdl
2个回答
1
投票

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

“ Real”常数是parameter s和localparam s。这些是编译时间(精化时间)常数。只有它们可以用于宽度声明。因此,您的情况可能会遇到很多问题。

第二点是,跨模块引用应该只能访问变量和函数的实例。 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;


0
投票

您的困难可能与Vivado中的错误有关,而不是与代码中的任何问题有关。通过接口传递参数是Vivado的许多错误方面之一。每个版本的Vivado都有不同的错误,这些错误是随机发生的,范围从无意义的错误消息,错误的阐述到崩溃。最重要的是,综合和模拟都具有不同的错误,并且在一个代码中起作用的代码可能在另一个代码中无效。

如果您愿意处理所有这些,以下示例将在Vivado综合的最新版本中使用。我使用2019.1。版进行了测试。

interface iface #(PARAM=1);
    logic [PARAM-1:0] t = 0;
endinterface

module test(iface i);
    wire [i.PARAM-1:0] var1;
    initial if ($bits(var1) != 42) $error("err1");

    localparam int PARAM2 = i.PARAM + 1;
    wire [PARAM2-1:0] var2;
    initial if ($bits(var2) != 43) $error("err2");
endmodule

module tb;
    iface #(42) my_iface ();
    test my_test (my_iface);
endmodule

请注意,这可能在Vivado模拟器中不起作用。请注意,因为某些错误仅在您将接口传递到多个层次结构之后才出现。

© www.soinside.com 2019 - 2024. All rights reserved.