基于接口参数化模块 (SystemVerilog)
Parameterizing a module based on an interface (SystemVerilog)
我在 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 模拟器。请注意,因为有些错误只会在您将接口向下传递到多个层次结构后才会出现。
我在 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 模拟器。请注意,因为有些错误只会在您将接口向下传递到多个层次结构后才会出现。