如何生成具有不同连接的接口数组?

时间:2017-11-13 15:49:13

标签: system-verilog

我已声明以下界面:

interface data_x #(parameter g_DataWidth = 8)
   (input ckrs_t ClkRs_ix);
   logic [g_DataWidth-1:0] data;
   bit         enable;
   ckrs_t ClkRs;

   always_comb begin
      ClkRs = ClkRs_ix;
   end
endinterface

接口具有数据总线和数据使能,并且它与时钟和复位信号相关联,这是一个typedef ckrs_t。

我有一个模块,它接受这些接口的参数数组:

module fourmclinks
   (...
    data_x packet_ox[NUMBER_OF_GBT_LINKS-1:0],
    data_x packet_ix[NUMBER_OF_GBT_LINKS-1:0],
    ...
    );

我遇到的问题是,我需要在顶级实体中声明这些data_x接口的数组,但每次都使用不同的ClkRs_ix输入时钟。 (它用于gbts,其中每个接收器都有自己的时钟和复位信号)。

我尝试了很多东西,包括这个:

   ckrs_t txclock_x;
   assign txclock_x.clk = GbtTxFrameClk40MHz_k;
   assign txclock_x.reset = GbtReset_r;
   data_x #(.g_DataWidth(g_FrameSize)) packet_ox[NUMBER_OF_GBT_LINKS-1:0](.ClkRs_ix(txclock_x));

   data_x #(.g_DataWidth(g_FrameSize)) packet_ix[NUMBER_OF_GBT_LINKS-1:0]();
   genvar                 linkiface;
   generate
      for(linkiface=1; linkiface < NUMBER_OF_GBT_LINKS+1; linkiface++) begin : linkgenerator
     assign packet_ix[linkiface-1].ClkRs_ix.clk =
                             GbtRxFrameClk40Mhz_kb4[linkiface];
     assign packet_ix[linkiface-1].ClkRs_ix.reset = GbtReset_r;
     assign packet_ix[linkiface-1].enable = 0;
     assign packet_ix[linkiface-1].data = RxDataAppSfpGbtUserData_4b80[linkiface];
      end
   endgenerate

因此进行空/虚/未分配/ ...接口数组声明,然后在生成循环中为其分配正确的信号。这模拟,但quartus没有编译它声称

  无法将

值分配给输入&#34; ClkRs_ix&#34;。

如何正确生成接口数组,每个接口都有不同的输入连接?请帮忙

1 个答案:

答案 0 :(得分:0)

我现在有点聪明,所以这里是问题的解决方案。但首先是问题:

  • 不可能仅从上面的data_x接口声明中的端口声明中删除“input”方向。如果这样做,则必须为data_x对象的每个实例手动分配时钟和重置行。这确实是可能的,但是在界面实例化过程中,人们失去了时钟和重置自动分配的所有优点

  • 在这种特殊情况下,无法建立虚拟接口,并在for循环中连接信号。造成这种情况的根本原因是always_comb的存在,它接收输入复位/时钟并将其分配给内部信号。因此,这个分配以及顶级实体中的复位和时钟的手动分配导致从两个源驱动这些信号,Quartus不会消化

所以我发现唯一可行的方法是:

声明data_x接口以按需生成always_comb:

interface data_x #(
          parameter g_hasClock = 1,
          parameter g_DataWidth = 8)
   (
    input ckrs_t ClkRs_ix
    );

   logic [g_DataWidth-1:0] data;
   bit         enable;
   ckrs_t ClkRs;

   generate
      if(g_hasClock) begin
     always_comb begin
        ClkRs = ClkRs_ix;
     end
      end
   endgenerate

endinterface // data_x

使用未绑定的ClkRs_ix实例化接口。注意 g_hasClock 的用法,它实例化没有always_comb块的data_x接口,因此Quartus停止抱怨多个驱动程序:

   data_x #(.g_DataWidth(g_FrameSize),
        .g_hasClock(0)) packet_ix[NUMBER_OF_GBT_LINKS-1:0]();

然后生成具有不同时钟的接口:

   genvar                 linkiface;
   generate
      for(linkiface=1; linkiface < NUMBER_OF_GBT_LINKS+1; linkiface++)
   begin : linkgenerator

     assign packet_ix[linkiface-1].ClkRs.clk = GbtRxFrameClk40Mhz_kb4[linkiface];
     assign packet_ix[linkiface-1].ClkRs.reset = GbtReset_r;
     assign packet_ix[linkiface-1].enable = 0;
     assign packet_ix[linkiface-1].data = RxDataAppSfpGbtUserData_4b80[linkiface];
      end
   endgenerate

这很有效。它不是那么好,因为我们必须手动完成它。仅仅为了完整性:如果所有接口的时钟都相同,那么上面的所有代码都归结为这个代码段:

  ckrs_t txclock_x, rxclock_x;
   assign txclock_x.clk = GbtTxFrameClk40MHz_k;
   assign txclock_x.reset = GbtReset_r;
   data_x #(.g_DataWidth(g_FrameSize)) packet_ox[NUMBER_OF_GBT_LINKS-1:0](.ClkRs_ix(txclock_x));

我确信这不是有史以来最好的解决方案,但它可以编译并提供所需的结果。