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