首页 > 解决方案 > 参数化打包结构中字段的位宽,以便模块可以推断在端口映射中使用的位宽

问题描述

也在讨论:

https://verificationacademy.com/forums/systemverilog/parameterizing-bit-widths-fields-packed-struct-so-modules-can-infer-bit-width-if-used-port-map-virtual-interface-interface-编译时配置的结构位宽

https://forums.xilinx.com/t5/Synthesis/Parameterizing-the-Bit-Widths-of-fields-in-a-packed-struct-so/td-p/1191678

我无法在 SystemVerilog 中实现我的意图,试图使用最新的语言功能来使我的代码更优雅、更简洁。用于合成**

我想完成以下任务:

我在过去的实验中大多是成功的,但我遇到了一个问题。

请看下面的简单接口定义:

interface MyInterface #(int DATA_W, ADDR_W) () ;

  typedef struct packed
    { logic valid
    ; logic [ADDR_W-1:0] addr
    ; logic [DATA_W-1:0] data
    ; } SimpleStruct;

  SimpleStruct bus;
  logic ready;

  modport SNK (input bus, output ready);
  modport SRC (output bus, input ready);

endinterface

对于这个例子,实例化一个接口并在我的 Top 模块中的一个简单模块的输入处使用它很容易:

module TopTest 
  ( input wire Clock
  , input wire Reset
  , input wire [31:0] In
  , output wire dummyOut
  ) ;

  MyInterface # ( 32, 3 ) my_interface ();

  assign my_interface.bus.data = In ;
  assign my_interface.bus.addr = 3'h3 ;

  InnerTest inst_mod_inner_test
    ( .Clock( Clock )
    , .Reset( Reset )
    , .Sink( my_interface )
    ) ;

  assign dummyOut = my_interface.ready ;

endmodule

我遇到的问题是我不想用字段位宽度参数化实际模块,因为我相信在编译时字段的位宽度应该已经建立并且可以访问。情况似乎并非如此,我想知道是否有什么我可以做的事情来完成推断接口中打包结构的位宽(记住是这种情况,因为我希望它参数化,我知道这很容易获取未在接口中定义但在包或模块中定义的结构字段的 $bits)

module InnerTest 
  ( input wire Clock
  , input wire Reset
  , MyInterface.SNK Sink
  ) ;

  localparam BIT_WIDTH_SINK_DATA = $bits( Sink.bus.data ) // this line errors out b/c sink is 'virtual'

  RAM # ( .DATA_WIDTH( BIT_WIDTH_SINK_DATA ) ) ram ( ... // etc

  ... other code to drive output ready of interface ...

endmodule

设计师想要使模块“可参数化”的原因有很多,我过去也采用过这种方法,但我对不重复信息非常感兴趣。如果我采用简单的方法,我会简单地参数化我的内部测试模块,以便我提供它 DATA_WIDTH,但是我将有两个数字要更新,还有很多我觉得我不需要的参数。我认为如果我能以某种方式简单地推断出参数化结构的特征,那将是最优雅的。在我看来,我正在寻找的信息在编译时是真正已知的。我似乎无法访问它,或者这是 SystemVerilog 的另一个不足之处。

在模拟中跟进 Q Dave 提到的解决方法在使用 QuestaSim 时非常有用,但现在在 QuestaSim 中遇到了不同的问题:

当实例中的实际接口是数组实例元素或在生成构造之下时,通过接口端口“sink”的参数引用“sink.bus.data”无效

解决方法是什么,我不明白为什么仅仅在生成语句中会影响下游的事情。在这种情况下,我使用 generate 语句在不同的 FIFO 实现之间进行选择,即发生错误的代码行上方的几层。

typedef sink.bus.data questasim_workaround;
localparam width = $bits(questasim_workaround);

跟进实验 我已经尝试过传入类型,而不是限制自己传入 DATA_W。

interface MyInterface #(int ADDR_W, type DATA_TYPE) () ;

  typedef struct packed
    { logic valid
    ; logic [ADDR_W-1:0] addr
    ; DATA_TYPE data
    ; } SimpleStruct;

  SimpleStruct bus;
  logic ready;

  modport SNK (input bus, output ready);
  modport SRC (output bus, input ready);

endinterface

这允许更大的灵活性。我观察到 Vivado 模拟器和综合工具可以毫无问题地处理这样的示例。

module SomeModule
  ( MyInterface myInt
  blah...
  );

  localparam SOMETHING = $bits(myInt.DATA_TYPE);
  // or equivalently
  localparam SOMETHING_ELSE = $bits(myInt.data);
  // or even this, for needs of a internal signal for pipelined processing steps
  MyInterface # ($bits(myInt.addr), myInt.DATA_TYPE) internal_0 () ;

在 QUEstaSim 中,我们不得不实施 Dave 的解决方法:

module SomeModule
  ( MyInterface myInt
  blah...
  );

  // this gets less elegant :/
  typedef myInt.data questasim_workaround_data;
  typedef myInt.addr questasim_workaround_addr;

  localparam SOMETHING = $bits(questasim_workaround_data);
  // or equivalently
  localparam SOMETHING_ELSE = $bits(questasim_workaround_data);
  // or even this, for needs of a internal signal for pipelined processing steps

  MyInterface # ($bits(questasim_workaround_addr), questasim_workaround_data) internal_0 () ;

标签: system-verilogvivado

解决方案


当前的 SystemVerilog BNF 不允许任何带点的“.”。参数初始化中的名称。但是你可以通过使用 typedef 来解决这个问题

interface MyInterface #(int DATA_W=0, ADDR_W=0) () ;
  typedef  logic [DATA_W-1:0]   data_t;
  ...
endinterface
 
module InnerTest 
  ( input wire Clock
  , input wire Reset
  , MyInterface.SNK Sink
  ) ;
 
  typedef Sink.data_t data_t;
  localparam BIT_WIDTH_SINK_DATA = $bits( data_t );
  ...
endmodule

推荐阅读