systemverilog 指定带参数的导入命名空间
systemverilog specify import namespace with parameter
我有一个 systemverilog 模块,它引用生成的头文件,其中包含各种类型定义和函数。这是可综合的代码。该模块之前工作正常,因为头文件是使用预处理器包含的。
现在我的架构发生了变化,我需要实例化这个模块的多个案例,并为每个实例指定不同的头文件。由于预处理器定义变量的全局性质,我认为预处理器方法不再有效。我不能为模块的一个实例包含一个头文件,而为另一个实例包含另一个头文件。正确吗?
所以我正在尝试使用包。我想做的是类似下面的事情:
package pack1;
parameter from_pack = 1;
typedef struct packed
{
logic [7:0] test1;
logic test2;
} test_t;
function automatic void hello();
$display("in pack1");
endfunction
endpackage
package pack2;
parameter from_pack = 2;
typedef struct packed
{
logic [7:0] test1;
logic test2;
logic [18:0] test3;
} test_t;
function automatic void hello();
$display("in pack2");
endfunction
endpackage
module top();
parameter PACKAGE_INST = 1;
generate
case (PACKAGE_INST)
1: begin
// import pack1::hello;
import pack1::*;
end
default: begin
// import pack2::hello;
import pack2::*;
end
endcase
// Error! Compiler doesn't know anything about the test_t type
test_t test_struct;
// pack1::test_t test_struct;
initial begin
$display("P1 = %d", P1);
// Error at elaboration! Simulator cannot find the 'hello()' function
hello();
// pack1::hello();
end
endgenerate
endmodule
请注意此代码的两个问题,这两个问题都与我无法指定要与参数一起使用的命名空间有关。我怀疑我的问题是参数更改不一定需要重新编译,而我试图影响的更改肯定需要重新编译。这适合我的申请;我不需要在不重新编译代码的情况下进行这些更改。
我能在 SO 上找到关于这个问题的最接近的讨论,至少在这里:
Handling parameterization in SystemVerilog packages
但最好的答案是使用预处理器魔法,我认为这对我的情况不起作用。我真的很感激对这个问题的任何见解。谢谢
您尝试做的事情的问题是 import 语句在它出现的 begin/end 范围内是本地的。您需要在每个分支中声明 test_struct 变量,不幸的是处理函数的唯一方法是编写一个包装器。
package pack1;
parameter from_pack = 1;
typedef struct packed
{
logic [7:0] test1;
logic test2;
} test_t;
function automatic void hello();
$display("in pack1");
endfunction
endpackage
package pack2;
parameter from_pack = 2;
typedef struct packed
{
logic [7:0] test1;
logic test2;
logic [18:0] test3;
} test_t;
function automatic void hello();
$display("in pack2");
endfunction
endpackage
module top();
parameter PACKAGE_INST = 1;
case (PACKAGE_INST)
1: begin : genscope
pack1::test_t test_struct;
function void hello;
pack1::hello();
endfunction
end
default: begin :genscope
pack2::test_t test_struct;
function void hello;
pack2::hello();
endfunction
end
endcase
initial begin
$display("PACKAGE_INST = %d", PACKAGE_INST);
$display("%p",genscope.test_struct);
genscope.hello();
end
endmodule
另一种完全不同的方法是使用接口而不是包。通过将您的模块连接到不同的接口实例,您可以 select 连接到模块的类型和功能。
interface intf1;
parameter from_intf = 1;
typedef struct packed
{
logic [7:0] test1;
logic test2;
} test_t;
function automatic void hello();
$display("in intf1");
endfunction
endinterface
interface intf2;
parameter from_intf = 2;
typedef struct packed
{
logic [7:0] test1;
logic test2;
logic [18:0] test3;
} test_t;
function automatic void hello();
$display("in intf2");
endfunction
endinterface
module DUT(interface itf);
typedef itf.test_t test_t; // LRM requires this so typename does not
// appear as a hierarchical reference
test_t test_struct;
initial begin
$display("%m from_intf = %d", itf.from_intf);
$display("%p",test_struct);
itf.hello();
end
endmodule
module top2;
intf1 i1();
intf2 i2();
DUT d1(i1);
DUT d2(i2);
endmodule
我有一个 systemverilog 模块,它引用生成的头文件,其中包含各种类型定义和函数。这是可综合的代码。该模块之前工作正常,因为头文件是使用预处理器包含的。
现在我的架构发生了变化,我需要实例化这个模块的多个案例,并为每个实例指定不同的头文件。由于预处理器定义变量的全局性质,我认为预处理器方法不再有效。我不能为模块的一个实例包含一个头文件,而为另一个实例包含另一个头文件。正确吗?
所以我正在尝试使用包。我想做的是类似下面的事情:
package pack1;
parameter from_pack = 1;
typedef struct packed
{
logic [7:0] test1;
logic test2;
} test_t;
function automatic void hello();
$display("in pack1");
endfunction
endpackage
package pack2;
parameter from_pack = 2;
typedef struct packed
{
logic [7:0] test1;
logic test2;
logic [18:0] test3;
} test_t;
function automatic void hello();
$display("in pack2");
endfunction
endpackage
module top();
parameter PACKAGE_INST = 1;
generate
case (PACKAGE_INST)
1: begin
// import pack1::hello;
import pack1::*;
end
default: begin
// import pack2::hello;
import pack2::*;
end
endcase
// Error! Compiler doesn't know anything about the test_t type
test_t test_struct;
// pack1::test_t test_struct;
initial begin
$display("P1 = %d", P1);
// Error at elaboration! Simulator cannot find the 'hello()' function
hello();
// pack1::hello();
end
endgenerate
endmodule
请注意此代码的两个问题,这两个问题都与我无法指定要与参数一起使用的命名空间有关。我怀疑我的问题是参数更改不一定需要重新编译,而我试图影响的更改肯定需要重新编译。这适合我的申请;我不需要在不重新编译代码的情况下进行这些更改。
我能在 SO 上找到关于这个问题的最接近的讨论,至少在这里:
Handling parameterization in SystemVerilog packages
但最好的答案是使用预处理器魔法,我认为这对我的情况不起作用。我真的很感激对这个问题的任何见解。谢谢
您尝试做的事情的问题是 import 语句在它出现的 begin/end 范围内是本地的。您需要在每个分支中声明 test_struct 变量,不幸的是处理函数的唯一方法是编写一个包装器。
package pack1;
parameter from_pack = 1;
typedef struct packed
{
logic [7:0] test1;
logic test2;
} test_t;
function automatic void hello();
$display("in pack1");
endfunction
endpackage
package pack2;
parameter from_pack = 2;
typedef struct packed
{
logic [7:0] test1;
logic test2;
logic [18:0] test3;
} test_t;
function automatic void hello();
$display("in pack2");
endfunction
endpackage
module top();
parameter PACKAGE_INST = 1;
case (PACKAGE_INST)
1: begin : genscope
pack1::test_t test_struct;
function void hello;
pack1::hello();
endfunction
end
default: begin :genscope
pack2::test_t test_struct;
function void hello;
pack2::hello();
endfunction
end
endcase
initial begin
$display("PACKAGE_INST = %d", PACKAGE_INST);
$display("%p",genscope.test_struct);
genscope.hello();
end
endmodule
另一种完全不同的方法是使用接口而不是包。通过将您的模块连接到不同的接口实例,您可以 select 连接到模块的类型和功能。
interface intf1;
parameter from_intf = 1;
typedef struct packed
{
logic [7:0] test1;
logic test2;
} test_t;
function automatic void hello();
$display("in intf1");
endfunction
endinterface
interface intf2;
parameter from_intf = 2;
typedef struct packed
{
logic [7:0] test1;
logic test2;
logic [18:0] test3;
} test_t;
function automatic void hello();
$display("in intf2");
endfunction
endinterface
module DUT(interface itf);
typedef itf.test_t test_t; // LRM requires this so typename does not
// appear as a hierarchical reference
test_t test_struct;
initial begin
$display("%m from_intf = %d", itf.from_intf);
$display("%p",test_struct);
itf.hello();
end
endmodule
module top2;
intf1 i1();
intf2 i2();
DUT d1(i1);
DUT d2(i2);
endmodule