我在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,但在其中找不到任何解决方案。
高度赞赏任何解决方案(不计算接口外部的派生参数并将其向下传递到层次结构中)或指向正确方向的指针。
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;
,
您的困难可能与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模拟器中不起作用。请注意,因为某些错误仅在您将接口传递到多个层次结构之后才出现。